【问题标题】:How to apply a color filter to a view with all children如何将滤色器应用于具有所有子项的视图
【发布时间】:2012-06-17 16:57:46
【问题描述】:

如何使包含许多不同项目的视图统一变灰 - ImageViews、TextViews、背景图像。我必须单独将每件事情变灰吗?或者有没有办法对所有人应用相同的颜色过滤器?

【问题讨论】:

    标签: android view colors filter


    【解决方案1】:

    这完全取决于您用于“灰显”项目的方法。如果您通过在父 ViewGroup 上调用 setEnabled(false) 来执行此操作,则默认情况下状态标志(如禁用)不会渗透到子视图。但是,您可以通过两种简单的方式进行自定义:

    一种选择是将属性 android:duplicateParentState="true" 添加到 XML 中的每个子视图。这将告诉孩子们从父母那里得到他们的州旗。然而,这将反映所有标志,包括按下、选中等...不仅仅是启用。

    另一种选择是创建您的ViewGroup 的自定义子类 并覆盖setEnabled() 以调用所有子视图,即

    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
    
        for(int i=0; i < getChildCount(); i++) {
            getChildAt(i).setEnabled(enabled);
        }
    }
    

    【讨论】:

    • 不,不,不禁用。变灰(颜色!)
    【解决方案2】:

    除非其他人有更好的答案,否则我目前的方法是将每个项目分别变灰。

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

    对于更多或嵌套的子级,带有 instanceof 的循环可能是合适的,但我不需要它。

    编辑:这个过滤器实际上并不是灰色的,这里有一个更好的过滤器:Drawable => grayscale 可以以同样的方式使用。

    【讨论】:

    • myLayout.getBackground().setColorFilter(greyFilter); 我正在搜索它。很棒的东西。
    • 我认为 Sam Lu 的答案是最准确的
    • 对于drawable,您可能需要使用drawable.mutate() 来确保颜色的一致性。因为默认情况下,颜色会被android框架缓存,并使同一个drawable的状态在应用程序之间共享。例如,如果您在MainActivity 中使用可绘制对象,则为其设置颜色过滤器。当您在DetailActivity 中使用相同的drawable 时,过滤器将自动应用于DetailActivity 中的drawable,因为它已被缓存。
    【解决方案3】:

    通过如下定义自定义视图组很容易做到这一点:

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

    MyViewContainer 的所有子视图都将显示为灰色。 :-)

    【讨论】:

    • 这就像一个魅力。您可以使用 ColorMatrix 来获得您想要的结果。
    【解决方案4】:

    Sam Lu 的回答是一个好的开始,但是我遇到了性能问题并决定切换到硬件层。使用硬件层,您可以这样做:

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

    注意不要在 dispatchDraw() 本身中做层,因为这会使应用程序崩溃。

    【讨论】:

    • 简单地切换到 LAYER_TYPE_HARDWARE 会导致 "W/OpenGLRenderer: Layer exceeds max. dimensions supported by the GPU (1088x4288, max=4096x4096)" 在大视图上崩溃。而"max=4096x4096" 取决于手机型号
    【解决方案5】:

    我喜欢创建一个与您尝试着色的视图重叠的视图,并将其背景设置为透明颜色。然后您可以通过设置视图可见性来打开和关闭色调

    <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>
    

    然后在你的控制器中:

    m_DisabledBlackTintOverlay = (View) view.findViewById(R.id.login_disabled_black_tint_overlay);
    
    m_DisabledBlackTintOverlay.setVisibility(View.VISIBLE);
    

    【讨论】:

      【解决方案6】:

      如果您需要做的只是淡出或淡化视图颜色,解决方案可以是

      View.setAlpha(@FloatRange(from=0.0, to=1.0) float alpha)
      

      这会改变整个视图的透明度

      【讨论】:

        猜你喜欢
        • 2015-05-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-15
        • 1970-01-01
        • 2019-07-27
        相关资源
        最近更新 更多