listview: how to handle delay between state pressed and activated

对着背影说爱祢 提交于 2019-12-23 03:48:10

问题


My goal
When the user taps an item in a listview the item changes background color until the list item is no longer activated (f.e. in single choice mode, the user taps another list item).

My problem
when tapped on an item in a listview briefly, there is a small delay between the pressed state and the activated state of the listview item; this causes the listview item to flash momentarily (because it reverts to unpressed state before the activated state is set).

This only happens when the tap duration is short, when you tap it longer there is no delay between the pressed state and the activated state.

I can produce the problem (on a Samsung S3 - Android 4.3) using this simple test code:

main.xml (containing listview definition)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:cacheColorHint="@android:color/white"
            android:background="@android:color/white"
            android:divider="@android:color/black"
            android:dividerHeight="1dp"
            android:choiceMode="singleChoice"
            />

</LinearLayout>

listitem.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/rootLayout"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal"
        android:background="@drawable/selector">
</LinearLayout>

selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@android:color/holo_blue_dark"/>
    <item android:state_activated="true" android:drawable="@android:color/holo_blue_dark"/>
    <item android:drawable="@android:color/white"/>
</selector>

MyActivity.java

package com.example.Test;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;

public class MyActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ListView listView = (ListView) findViewById(R.id.listView);
        listView.setAdapter(new ListAdapter(this,
                new String[] {"item 1", "item 2", "item 3", "item 4"}));
    }

    private class ListAdapter extends ArrayAdapter<String> {
        public ListAdapter(Context context, String[] objects) {
            super(context, 0, objects);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = new ListItemView(getContext());
            }

            return convertView;
        }
    }

    private class ListItemView extends LinearLayout {
        public ListItemView(Context context) {
            super(context);
            LayoutInflater.from(context).inflate(R.layout.listitem, this, true);
        }
    }
}

already tried
Setting the activated state manually in the OnItemClickListener. Doesn't help.

ugly hack
Adding the following code to my ListItemView class seems to work, but it also looks like an ugly hack:

@Override
public void setPressed(boolean pressed) {
    if (pressed) {
        super.setPressed(true);
    } else {
        postDelayed(new Runnable() {
            @Override
            public void run() {
                ListItemView.super.setPressed(false);
            }
        }, 100);
    }
}

basically, this delays setting the state to unpressed, so the activated state is always set first (that is, when the delay is long enough).


回答1:


Did you finaly find a solution ? The best workaround I have found so far to avoid the 'flicker' is to add an exitFadeDuration, for example in the background selector (it works also in the list selector):

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
       android:exitFadeDuration="_some_integer_value_>">
    <item android:state_pressed="true" android:drawable="@android:color/holo_blue_dark"/>
    <item android:state_activated="true" android:drawable="@android:color/holo_blue_dark"/>
    <item android:drawable="@android:color/white"/>
</selector>

100 ms seems enough, @android:integer/config_shortAnimTime is a bit too slow for my taste



来源:https://stackoverflow.com/questions/22422638/listview-how-to-handle-delay-between-state-pressed-and-activated

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!