Android Lollipop以降のlistViewアイテムに簡単な波及効果を追加したいと思います。
最初に単純な行に設定し、次に9パッチ行、さらにはCardViewに設定したいと思います。
通常のセレクターを定義する必要さえないので、これは非常に簡単になると確信していました。単純な行でもそうすることができませんでした。何らかの理由で、波及効果は行の境界を超えています。
それだけでなく、場合によっては、アイテムの背景が設定した色に固定されることがあります。
これは私が試したものです:
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バージョン)の通常のセレクターがあります
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:Android="http://schemas.Android.com/apk/res/Android" />
上記の単純なコードとは別に、ListViewで「listSelector」を使用する代わりに、アイテムのbackgroundプロパティごとにセレクターを設定しようとしましたが、役に立ちませんでした。
私が試したもう1つのことは、アイテムの前景を設定することですが、同じ結果になりました。
この問題を修正するにはどうすればよいですか?なぜそれが起こるのですか?私は何を間違えましたか?
9パッチ、さらには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>
それでも、バックグラウンドがスタックするという問題があり、不足している残りの機能(9パッチ、cardViewなど)を処理する方法が見つかりません。
色が詰まっているのは、それをビューの前景として使用することと関係があると思います。
編集:ここでの質問が何であるかを理解していない人がいるようです。
古いセレクター/ CardViewを使用しながら、新しい波及効果を処理することです。
たとえば、セレクタードローブルは次のとおりです。
<?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>
これは、リストセレクターまたは単一ビューの背景として使用できます。
ただ、リップルドローアブルと一緒に使う方法がわかりません。
私は波紋がすでにいくつかの州を処理していることを知っていますが、一部の州ではそうではありません。さらに、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);
}
RippleDrawable
はLayerDrawable
を拡張します。タッチフィードバックドローアブルには、画面に描画されない特別なマスクレイヤーを含む、複数の子レイヤーが含まれる場合があります。 Android:id
値をmask
として指定することにより、単一のレイヤーをマスクとして設定できます。 2番目のレイヤーはStateListDrawable
にすることができます。
たとえば、名前がitem_selectable.xml
の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>
セレクターとともに波及効果を実現するために、上記のdrawableをRippleDrawable
のレイヤーとしてlist_selector_ripple.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">
<color Android:color="@Android:color/white"/>
</item>
<item Android:drawable="@drawable/item_selectable"/>
</ripple>
PD:
1)このドローアブルをCardView
で使用するには、次のようにAndroid:foreground
として設定します。
<Android.support.v7.widget.CardView
...
Android:foreground="@drawable/list_selector_ripple"
/>
2)リップル効果を9パッチの範囲内で機能させるには、この9パッチドローアブルをリップルドローアブルのマスクとして設定する必要があります(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"
/>
リップルを作成する簡単な方法は、drawable-v21フォルダーにxmlを作成し、このコードをxmlに使用します。
Android:backgroung="@drawable/ripple_xyz"
そして、もし、Through Java /動的に使用します。
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>
このチュートリアルを確認してください。波及効果は実装されており、正常に機能しています。 RecyclerViewへの波及効果
リップルにマスクレイヤーを設定する必要があります。
このようなもの:
<?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>
以下のコードのようなもので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パッチイメージです