色调/暗淡触摸

我目前正在使用的应用程序使用了很多ImageView作为button。 这些button上的graphics使用alpha通道淡出button的边缘,使其看起来不规则。 目前,我们必须为每个button生成2个graphics(1个用于选定/聚焦/按下的状态,另一个用于默认的未选中状态),并使用每个button的XML文件中定义的StateListDrawable。

虽然这工作得很好,但看起来非常浪费,因为所有选定的graphics都是未选button的简单着色版本。 这些需要花费时间(尽pipe很less),并占用最终APK的空间。 似乎应该有一个简单的方法来自动。

看起来,完美的解决scheme是为每个button使用ImageView,并在其tint属性中指定一个ColorStateList。 这种方法的优点是,所有的button(共享相同的色调)只需要一个XML ColorStateList。 但是它不起作用。 如上所述,当提供给tint的值不是单一颜色时,ImageView将抛出NumberFormatExceptionexception。

我的下一个尝试是为选定的绘图使用一个LayerDrawable。 在图层列表中,我们将在半透明矩形的底部覆盖原始图像。 这工作在buttongraphics的固体部分。 然而,应该是完全透明的边缘现在与顶层一样的颜色。

有没有人遇到过这个问题,并find合理的解决办法? 我想坚持XML的方法,但可能会编码一个简单的ImageView子类,将执行所需的代码着色。

Solutions Collecting From Web of "色调/暗淡触摸"

你可以StateListDrawable组合StateListDrawableLayerDrawable

 public Drawable getDimmedDrawable(Drawable drawable) { Resources resources = getContext().getResources(); StateListDrawable stateListDrawable = new StateListDrawable(); LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{ drawable, new ColorDrawable(resources.getColor(R.color.translucent_black)) }); stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, layerDrawable); stateListDrawable.addState(new int[]{android.R.attr.state_focused}, layerDrawable); stateListDrawable.addState(new int[]{android.R.attr.state_selected}, layerDrawable); stateListDrawable.addState(new int[]{}, drawable); return stateListDrawable; } 

我假设我们的colors.xml如下所示

 <?xml version="1.0" encoding="utf-8"?> <resources> <color name="translucent_black">#80000000</color> </resources> 

对于那些遇到类似需求的人来说,在代码中解决这个问题相当干净。 这是一个示例:

 public class TintableButton extends ImageView { private boolean mIsSelected; public TintableButton(Context context) { super(context); init(); } public TintableButton(Context context, AttributeSet attrs) { super(context, attrs); init(); } public TintableButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { mIsSelected = false; } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN && !mIsSelected) { setColorFilter(0x99000000); mIsSelected = true; } else if (event.getAction() == MotionEvent.ACTION_UP && mIsSelected) { setColorFilter(Color.TRANSPARENT); mIsSelected = false; } return super.onTouchEvent(event); } } 

它还没有完成,但作为一个概念certificate很好。

你的回答非常好:)

然而,不是创build一个button对象,我只是调用一个OnTouchlistener来改变每个视图的状态。

 public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { Drawable background = v.getBackground(); background.setColorFilter(0xBB000000, PorterDuff.Mode.SCREEN); v.setBackgroundDrawable(background); } else if (event.getAction() == MotionEvent.ACTION_UP) { Drawable background = v.getBackground(); background.setColorFilter(null); v.setBackgroundDrawable(background); } return true; } 

虽然给出了相同的结果

我觉得这个解决scheme很简单!

第1步:创buildres / drawable / dim_image_view.xml

 <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_focused="true" android:drawable="@drawable/dim_image_view_normal"/> <!-- focused --> <item android:state_pressed="true" android:drawable="@drawable/dim_image_view_pressed"/> <!-- pressed --> <item android:drawable="@drawable/dim_image_view_normal"/> <!--default --> </selector> 

第2步:创buildres / drawable / dim_image_view_normal.xml

 <?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item><bitmap android:src="@mipmap/your_icon"/></item> </layer-list> 

第3步:创buildres / drawable / dim_image_view_pressed.xml

 <?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item><bitmap android:src="@mipmap/your_icon" android:alpha="0.5"></bitmap></item> </layer-list> 

第4步:尝试在xml布局中设置图像为:

 android:src="@drawable/dim_image_view" 

我也有不规则的button,需要色调。 最后,我只是采取了一个状态的颜色列表作为我的ImageButton背景。 给人的印象是button的颜色在按下时变化,非常简单,计算密集度也较低。 我知道这不完全是一个色彩,但它确实给它在用户通常是稍纵即逝的瞬间提供必要的视觉反馈。

 <?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/darker_gray" /> <item android:drawable="@android:color/transparent" /> </selector> 

你的回答也很好;)

我正在修改一点,它会给你这样的结果:

button_normalbutton_pressed

 Rect rect; Drawable background; boolean hasTouchEventCompleted = false; @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom()); hasTouchEventCompleted = false; background = v.getBackground(); background.setColorFilter(0x99c7c7c7, android.graphics.PorterDuff.Mode.MULTIPLY); v.setBackgroundDrawable(background); } else if (event.getAction() == MotionEvent.ACTION_UP && !hasTouchEventCompleted) { background.setColorFilter(null); v.setBackgroundDrawable(background); } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) { // User moved outside bounds background.setColorFilter(null); v.setBackgroundDrawable(background); hasTouchEventCompleted = true; } } //Must return false, otherwise you need to handle Click events yourself. return false; } 

我认为这个解决scheme很简单:

  final Drawable drawable = ... ; final int darkenValue = 0x3C000000; mButton.setOnTouchListener(new OnTouchListener() { Rect rect; boolean hasColorFilter = false; @Override public boolean onTouch(final View v, final MotionEvent motionEvent) { switch (motionEvent.getAction()) { case MotionEvent.ACTION_DOWN: rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom()); drawable.setColorFilter(darkenValue, Mode.DARKEN); hasColorFilter = true; break; case MotionEvent.ACTION_MOVE: if (rect.contains(v.getLeft() + (int) motionEvent.getX(), v.getTop() + (int) motionEvent.getY())) { if (!hasColorFilter) drawable.setColorFilter(darkenValue, Mode.DARKEN); hasColorFilter = true; } else { drawable.setColorFilter(null); hasColorFilter = false; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: drawable.setColorFilter(null); hasColorFilter = false; break; } return false; } });