How to apply a color filter to a view with all children

前端 未结 5 496
误落风尘
误落风尘 2020-12-24 02:45

How do I grey out a view uniformly which contains many different items - ImageViews, TextViews, background image. Do I have to grey out each thing individually? Or is there

相关标签:
5条回答
  • 2020-12-24 02:59

    Unless somebody else has a better answer, my current method is greying out each item separatedly.

    PorterDuffColorFilter greyFilter = new PorterDuffColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
    myLayout.getBackground().setColorFilter(greyFilter);
    myImageView.setColorFilter(greyFilter);
    myTextView.setTextColor(0xff777777);
    

    For more or nested children probably a loop with instanceof would be suitable but I don't need it.

    Edit: This filter isn't actually grey, a better filter is here: Drawable => grayscale Which can be used in the same way.

    0 讨论(0)
  • 2020-12-24 03:03

    It depends entirely on the method you are using to "gray out" items. If you are doing so by calling setEnabled(false) on the parent ViewGroup, by default state flags (like disabled) do not trickle down to the child views. However, there are two simple ways you can customize this:

    One option is to add the attribute android:duplicateParentState="true" to each child view in your XML. This will tell the children to get their state flags from the parent. This will mirror ALL flags however, including pressed, checked, etc...not just enabled.

    Another option is to create a custom subclass of your ViewGroup and override setEnabled() to call all the child views as well, i.e.

    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
    
        for(int i=0; i < getChildCount(); i++) {
            getChildAt(i).setEnabled(enabled);
        }
    }
    
    0 讨论(0)
  • 2020-12-24 03:05

    What I like to do is create a view which overlaps the view you are trying to tint and set its background to a transparent color. Then you can turn the tint on and off by setting that views visibility

    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ViewYouWantToTint
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
        <View
            android:id="@+id/disabled_tint_overlay"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/darkTint"
            android:visibility="invisible"/>
    
    </FrameLayout>
    

    Then in your controller:

    m_DisabledBlackTintOverlay = (View) view.findViewById(R.id.login_disabled_black_tint_overlay);
    
    m_DisabledBlackTintOverlay.setVisibility(View.VISIBLE);
    
    0 讨论(0)
  • 2020-12-24 03:10

    It's easy to do that by defining a custom view group as follows:

    public class MyViewContainer extends XXXLayout {
        //XXLayout could be LinearLayout, RelativeLayout or others
        private Paint m_paint;
    
        //define constructors here and call _Init() at the end of constructor function
    
        private void
        _Init()
        {
            ColorMatrix cm = new ColorMatrix();
            cm.setSaturation(0);
            m_paint = new Paint();
            m_paint.setColorFilter(new ColorMatrixColorFilter(cm));
        }
    
        @Override protected void 
        dispatchDraw(Canvas canvas)
        {
            canvas.saveLayer(null, m_paint, Canvas.ALL_SAVE_FLAG);
            super.dispatchDraw(canvas);
            canvas.restore();
        }
    }
    

    All children views of MyViewContainer will be shown in grey. :-)

    0 讨论(0)
  • 2020-12-24 03:18

    Sam Lu's answer is a good start, but I had performance problems and decided to switch to hardware layers. With hardware layers, you can do it like this:

    private final Paint grayscalePaint = new Paint();
    
    ColorMatrix cm = new ColorMatrix();
    cm.setSaturation(0);        
    grayscalePaint.setColorFilter(new ColorMatrixColorFilter(cm));
    
    public void setGrayedOut(boolean grayedOut) {       
        if (grayedOut) {
            setLayerType(View.LAYER_TYPE_HARDWARE, grayscalePaint);
        } else {
            setLayerType(View.LAYER_TYPE_NONE, null);       
        }       
    }
    

    Be careful not to do the layers in dispatchDraw() itself as that will crash the app.

    0 讨论(0)
提交回复
热议问题