如何将滤色器应用于具有所有子项的视图
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)
这会改变整个视图的透明度
【讨论】:
以上是关于如何将滤色器应用于具有所有子项的视图的主要内容,如果未能解决你的问题,请参考以下文章