如何在自定义listView上创建自定义listSelector

时间:2014-11-30 14:11:36

标签: android listview

我试图弄清楚如何在listView中设置自定义listSelector。代码或多或少地复制和粘贴来自在stackoverflow中为其他人工作的解决方案,但它对我来说并不起作用。

当我打开CAB模式时,我可以选择和取消选择项目,并且我在CAB导航栏中看到所选项目的数量,但我在列表中看不到任何指示。我想看看哪些项目被选中。知道它为什么不起作用吗?

布局/ category_list.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/categories_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <ListView
            android:id="@+id/category_browser"
            android:layout_width="match_parent"
            android:layout_height="0dip"
            android:layout_weight="1"
            android:dividerHeight="1dp"
                    android:listSelector="@drawable/list_selector"
                    android:drawSelectorOnTop="true"
            tools:listitem="@layout/category_list_item" >
    </ListView>
    <include layout="@layout/ad"/>
</LinearLayout>

布局/ category_list_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<com.fletech.smartbaby.api.CheckableLinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/category_browser_list_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="fill"
        android:clickable="true"
        android:gravity="fill"
        android:orientation="horizontal">
        <ImageView
                android:id="@+id/category_item_icon"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:layout_gravity="fill"
                android:layout_weight="0"
                        android:background="#ffffff"
                android:src="@drawable/ic_launcher" />
        <TextView
                android:id="@+id/category_browser_list_title"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center_vertical|start"
                android:paddingLeft="10dp"
                android:paddingRight="10dp"
                        tools:text="Category name"
                android:textColor="#000000"
                android:textSize="24sp" />

        <include layout="@layout/category_features"
            android:layout_centerInParent="true"
            android:layout_alignParentRight="true"
            android:layout_alignParentEnd="true"
            />

        <include layout="@layout/category_status"
            android:layout_centerInParent="true"
            android:layout_alignParentRight="true"
            android:layout_alignParentEnd="true"
            />
</com.fletech.smartbaby.api.CheckableLinearLayout>

抽拉/ list_selector.xml:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#40777777"/>
        </shape>
    </item>
    <item android:state_long_pressable="true">
        <shape android:shape="rectangle">
            <solid android:color="#400000ff"/>
        </shape>
    </item>
    <item android:state_checkable="true">
        <shape android:shape="rectangle">
            <solid android:color="#400000ff"/>
        </shape>
    </item>
    <item android:state_checked="true">
        <shape android:shape="rectangle">
            <solid android:color="#800000ff"/>
        </shape>
    </item>
</selector>

和CheckableLinearLayout.java:

package com.fletech.smartbaby.api;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
//import android.support.v7.widget.LinearLayoutCompat; // do I need this? I can't see any difference
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Checkable;
import android.widget.LinearLayout;

public class CheckableLinearLayout extends LinearLayout implements Checkable {
    private static final String TAG = CheckableLinearLayout.class.getSimpleName();
    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};

    private boolean mChecked;

    public CheckableLinearLayout(Context context) {
        super(context);
    }

    public CheckableLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public CheckableLinearLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void setChecked(boolean checked) {
        Log.v(TAG, "setChecked: " + checked);
        if (mChecked != checked) {
            mChecked = checked;
            refreshDrawableState();
        }
    }

    @Override
    public boolean isChecked() {
        return mChecked;
    }

    @Override
    public void toggle() {
        Log.v(TAG, "toggle: " + mChecked + " -> " + (!mChecked));
        setChecked(!mChecked);
    }

    @Override
    // not sure if needed, as it seems to work without this as well
    public boolean performClick() {
        Log.v(TAG, "performClick");
        toggle();
        return super.performClick();
    }

    @Override
    // this might be unnecessary
    protected void drawableStateChanged() {
        Log.v(TAG, "drawableStateChanged");
        super.drawableStateChanged();
        final Drawable drawable=getBackground();
        if(drawable!=null)
        {
            final int[] myDrawableState=getDrawableState();
            drawable.setState(myDrawableState);
            invalidate();
        }
    }

    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        Log.v(TAG, "onCreateDrawableState: " + extraSpace);
        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
        if (isChecked()) {
            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
        }

        return drawableState;
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        SavedState result = new SavedState(super.onSaveInstanceState());
        result.checked = mChecked;
        return result;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (!(state instanceof SavedState)) {
            super.onRestoreInstanceState(state);
            return;
        }

        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());

        setChecked(ss.checked);
    }

    protected static class SavedState extends BaseSavedState {
        protected boolean checked;

        protected SavedState(Parcelable superState) {
            super(superState);
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(checked ? 1 : 0);
        }

        public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };

        private SavedState(Parcel in) {
            super(in);
            checked = in.readInt() == 1;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

我花了一个多星期才发现为什么这个对每个人都有用的东西对我不起作用。答案很简单。我希望它能帮助别人。

解决方案是更改选择器xml中项目的顺序。没有任何状态的项目必须是最后一个:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_long_pressable="true">
        <shape android:shape="rectangle">
            <solid android:color="#400000ff"/>
        </shape>
    </item>
    <item android:state_checkable="true">
        <shape android:shape="rectangle">
            <solid android:color="#400000ff"/>
        </shape>
    </item>
    <item android:state_checked="true">
        <shape android:shape="rectangle">
            <solid android:color="#800000ff"/>
        </shape>
    </item>

    <!-- the item without any states has to be the last: -->
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#40777777"/>
        </shape>
    </item>
</selector>

原因是解析器似乎在xml文件中查找匹配的第一项。这意味着如果您有具有不同状态数的项目,那么您应始终拥有在xml顶部定义更多状态的项目。例如:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checkable="true" android:state_long_pressable="true">
        <shape android:shape="rectangle">
            <solid android:color="#ffff00"/>
        </shape>
    </item>
    <item android:state_long_pressable="true">
        <shape android:shape="rectangle">
            <solid android:color="#ff0000"/>
        </shape>
    </item>
    <item android:state_checkable="true">
        <shape android:shape="rectangle">
            <solid android:color="#00ff00"/>
        </shape>
    </item>
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#40777777"/>
        </shape>
    </item>
</selector>

这样,只有这样,你才会看到以下项目的不同颜色: - 可检查和long_pressable - 可检查,但不能长按 - long_pressable但不可检查 - 其他一切