如何处理9-patch和CardView上的纹波效应,并控制select器的状态?

背景

我希望为Android棒棒糖及以上版本的listView项目添加一个简单的连锁效果。

首先我要设置它为简单的行,然后到9补丁行甚至CardView。

问题

我确信这个会很容易,因为它甚至不需要我定义正常的select器。 即使对于简单的行,我也没有这样做。 由于某种原因,连锁反应超出了行的边界:

在这里输入图像说明

不仅如此,在某些情况下,该项目的背景会卡住我设定的颜色。

代码

这是我试过的:

MainActivity.java

public class MainActivity extends ActionBarActivity { @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final ListView listView = (ListView) findViewById(android.R.id.list); final LayoutInflater inflater = LayoutInflater.from(this); listView.setAdapter(new BaseAdapter() { @Override public View getView(final int position, final View convertView, final ViewGroup parent) { View rootView = convertView; if (rootView == null) { rootView = inflater.inflate(android.R.layout.simple_list_item_1, parent, false); ((TextView) rootView.findViewById(android.R.id.text1)).setText("Test"); } return rootView; } @Override public long getItemId(final int position) { return 0; } @Override public Object getItem(final int position) { return null; } @Override public int getCount() { return 2; } }); } } 

activity_main.xml中

 <?xml version="1.0" encoding="utf-8"?> <ListView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:cacheColorHint="@android:color/transparent" android:divider="@null" android:dividerHeight="0px" android:fadeScrollbars="false" android:fastScrollEnabled="true" android:listSelector="@drawable/listview_selector" android:scrollingCache="false" android:verticalScrollbarPosition="right" /> 

res / drawable-v21 / listview_selector.xml (我有其他Android版本的普通select器)

 <?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" /> 

我试过了

除了上面简单的代码之外,我还尝试设置每个项目的背景属性的select器,而不是使用ListView上的“listSelector”,但它没有帮助。

我试过的另一件事是设置项目的前景,但它也有相同的结果。

这个问题

我该如何解决这个问题? 为什么会发生? 我做错了什么?

如何进一步,支持9-patch,甚至CardView?

另外,如何设置新的背景的状态,如被选中/选中?


更新:视图之外的绘图使用这样的东西是固定的:

 <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?attr/colorControlHighlight" > <item android:id="@android:id/mask"> <color android:color="@color/listview_pressed" /> </item> </ripple> 

不过,它有背景被卡住的问题,我找不到如何处理其他缺失的function(9-patch,cardView,…)。

我认为被卡住的颜色与使用它作为视图的前景有关。


编辑:我看到有些人不明白这里的问题是什么。

这是关于处理新的涟漪效应,同时还有较老的select器/ CardView。

例如,这里有一个select器可用:

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

这可以用作列表select器或单个视图的背景。

但是,我无法find如何使用它与可绘制的波纹。

我知道涟漪已经照顾了一些国家,但是对于一些国家来说,事实并非如此。 另外,我无法find如何使它处理9补丁和CardView。

我希望现在能更容易地理解我的问题。


关于涟漪的颜色问题得到“窒息”,我想这是因为我的布局。 我想要一个布局,可以检查(当我决定),也有点击的效果,所以这就是我所做的(基于本网站和另一个,我找不到):

 public class CheckableRelativeLayout extends RelativeLayout implements Checkable { private boolean mChecked; private static final String TAG = CheckableRelativeLayout.class.getCanonicalName(); private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked }; private Drawable mForegroundDrawable; public CheckableRelativeLayout(final Context context) { this(context, null, 0); } public CheckableRelativeLayout(final Context context, final AttributeSet attrs) { this(context, attrs, 0); } public CheckableRelativeLayout(final Context context, final AttributeSet attrs, final int defStyle) { super(context, attrs, defStyle); final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CheckableRelativeLayout, defStyle, 0); setForeground(a.getDrawable(R.styleable.CheckableRelativeLayout_foreground)); a.recycle(); } public void setForeground(final Drawable drawable) { this.mForegroundDrawable = drawable; } public Drawable getForeground() { return this.mForegroundDrawable; } @Override protected int[] onCreateDrawableState(final int extraSpace) { final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); if (isChecked()) { mergeDrawableStates(drawableState, CHECKED_STATE_SET); } return drawableState; } @Override protected void drawableStateChanged() { super.drawableStateChanged(); final Drawable drawable = getBackground(); boolean needRedraw = false; final int[] myDrawableState = getDrawableState(); if (drawable != null) { drawable.setState(myDrawableState); needRedraw = true; } if (mForegroundDrawable != null) { mForegroundDrawable.setState(myDrawableState); needRedraw = true; } if (needRedraw) invalidate(); } @Override protected void onSizeChanged(final int width, final int height, final int oldwidth, final int oldheight) { super.onSizeChanged(width, height, oldwidth, oldheight); if (mForegroundDrawable != null) mForegroundDrawable.setBounds(0, 0, width, height); } @Override protected void dispatchDraw(final Canvas canvas) { super.dispatchDraw(canvas); if (mForegroundDrawable != null) mForegroundDrawable.draw(canvas); } @Override public boolean isChecked() { return mChecked; } @Override public void setChecked(final boolean checked) { setChecked(checked, true); } public void setChecked(final boolean checked, final boolean alsoRecursively) { mChecked = checked; refreshDrawableState(); if (alsoRecursively) ViewUtil.setCheckedRecursively(this, checked); } @Override public void toggle() { setChecked(!mChecked); } @Override public Parcelable onSaveInstanceState() { // Force our ancestor class to save its state final Parcelable superState = super.onSaveInstanceState(); final SavedState savedState = new SavedState(superState); savedState.checked = isChecked(); return savedState; } @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public void drawableHotspotChanged(final float x, final float y) { super.drawableHotspotChanged(x, y); if (mForegroundDrawable != null) { mForegroundDrawable.setHotspot(x, y); } } @Override public void onRestoreInstanceState(final Parcelable state) { final SavedState savedState = (SavedState) state; super.onRestoreInstanceState(savedState.getSuperState()); setChecked(savedState.checked); requestLayout(); } // ///////////// // SavedState // // ///////////// private static class SavedState extends BaseSavedState { boolean checked; SavedState(final Parcelable superState) { super(superState); } private SavedState(final Parcel in) { super(in); checked = (Boolean) in.readValue(null); } @Override public void writeToParcel(final Parcel out, final int flags) { super.writeToParcel(out, flags); out.writeValue(checked); } @Override public String toString() { return TAG + ".SavedState{" + Integer.toHexString(System.identityHashCode(this)) + " checked=" + checked + "}"; } @SuppressWarnings("unused") public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() { @Override public SavedState createFromParcel(final Parcel in) { return new SavedState(in); } @Override public SavedState[] newArray(final int size) { return new SavedState[size]; } }; } } 

编辑:修复是为我所做的布局添加下一行:

 @SuppressLint("ClickableViewAccessibility") @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public boolean onTouchEvent(final MotionEvent e) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && // e.getActionMasked() == MotionEvent.ACTION_DOWN && // mForeground != null) mForeground.setHotspot(e.getX(), e.getY()); return super.onTouchEvent(e); } 

Solutions Collecting From Web of "如何处理9-patch和CardView上的纹波效应,并控制select器的状态?"

RippleDrawable扩展了LayerDrawable 。 触摸反馈可绘制可能包含多个子图层,包括未画在屏幕上的特殊遮罩图层。 通过指定其android:id值作为mask可以将单个图层设置为mask 。 第二层可以是StateListDrawable

例如,下面是我们的StateListDrawable资源:

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

为了实现连同select器的涟漪效应,我们可以将上面的图层设置为一个名为list_selector_ripple.xmlRippleDrawable层:

 <?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@color/colorControlHighlight"> <item android:id="@android:id/mask"> <color android:color="@android:color/white"/> </item> <item android:drawable="@drawable/item_selectable"/> </ripple> 

UPD:

1)要使用CardView这个可绘制的设置为android:foreground ,像这样:

 <android.support.v7.widget.CardView ... android:foreground="@drawable/list_selector_ripple" /> 

2)为了使涟漪效应在9-patch的范围内工作,我们应该将这个9-patch设置为可绘制波纹的掩码( list_selector_ripple_nine_patch.xml ):

 <?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@color/colorControlHighlight"> <item android:id="@android:id/mask" android:drawable="@drawable/your_nine_patch" /> <item android:drawable="@drawable/your_nine_patch" /> </ripple> 

然后设置视图的背景:

 <LinearLayout ... android:background="@drawable/list_selector_ripple_nine_patch" /> 

简单的方法来创build一个涟漪在drawable-v21文件夹中创build一个xml,并将此代码用于xml。

 android:backgroung="@drawable/ripple_xyz" 

如果,通过java /dynamic使用。

 View.setBackgroundResource(R.drawable.ripple_xyz); 

这里是ripple_xyz.xml。

 <?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="#228B22" > // ^ THIS IS THE COLOR FOR RIPPLE <item> <shape android:shape="rectangle" android:useLevel="false" > <solid android:color="#CCFFFFFF" /> // ^ THIS IS THE COLOR FOR BACK GROUND </shape> </item> 

您必须在纹波中设置遮罩层。

像这样的东西:

 <?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?attr/colorControlHighlight"> <item android:id="@id/mask"> <color android:color="@color/myColor" /> </item> </ripple> 

检查这个教程。 涟漪效应是实现的,其工作正常。 对RecyclerView的涟漪效应

你可以像下面的代码一样处理9个补丁图像:

  <?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?attr/colorControlHighlight" > <item android:id="@android:id/mask" android:drawable="@drawable/comment_background"> </item> </ripple> 

其中comment_background是9个补丁映像