首页 文章

浅色/暗淡触感

提问于
浏览
16

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

虽然这很好用但看起来非常浪费,因为所有选定的图形都只是未选定按钮的着色版本 . 这些花费时间来制作(无论多少)并占用最终APK中的空间 . 似乎应该有一个简单的方法来自动 .

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

我的下一次尝试是为选定的drawable使用LayerDrawable . 在图层列表中,我们将原始图像放在堆栈底部,由半透明矩形覆盖 . 这适用于按钮图形的实体部分 . 然而,应该是完全透明的边缘现在与顶层的颜色相同 .

有没有人遇到过这个问题,找到了合理的解决方案?我想坚持使用XML方法,但可能会编写一个简单的ImageView子类,它将在代码中进行所需的着色 .

8 回答

  • 6

    您可以将 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>
    
  • 1

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

    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);
        }
    }
    

    它还没有完成,但作为一个概念证明 .

  • 1

    Your answer很棒:)

    但是,我只是调用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;
    
    }
    

    但是给出了相同的结果

  • 17

    我认为这个解决方案很简单!

    第1步:创建res / 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步:创建res / 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步:创建res / 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"
    
  • 1

    我也有不规则的按钮,需要色调 . 最后,我只是使用州的颜色列表作为我的 ImageButton 背景 . 给人的印象是按钮颜色在印刷时正在变化,并且非常简单且计算密集度较低 . 我知道这不完全是一种色调,但确实给它提供了必要的视觉反馈,通常是一个短暂的时刻 .

    <?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>
    
  • 2

    你可以使用我创建的类https://github.com/THRESHE/TintableImageButton不是最好的解决方案,但它有效 .

  • 6

    Your answer也很出色;)

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

    button_normal

    button_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;
    }
    
  • 0

    我认为这个解决方案很简单:

    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;
            }
        });
    

相关问题