如何将滤色器应用于具有所有子项的视图

Posted

技术标签:

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

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

【问题讨论】:

【参考方案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_
    android:layout_>

    <ViewYouWantToTint
        android:layout_
        android:layout_/>

    <View
        android:id="@+id/disabled_tint_overlay"
        android:layout_
        android:layout_
        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)

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

【讨论】:

以上是关于如何将滤色器应用于具有所有子项的视图的主要内容,如果未能解决你的问题,请参考以下文章

如何在android中的图像上应用不同的滤色器?

如何使用 GPUImageLibrary“减去”滤色器?

ffmpeg:如何使用 ffmpeg 在视频中仅放置颜色叠加视频或应用不同类型的滤色器(如 instagram)

更改屏幕的滤色器以与多台显示器一起使用

css 背景CSS图像适合屏幕并具有滤色器

如何向图像添加滤色器,以使其平均 RGB 更接近该颜色?