以编程方式使视图变暗

Posted

技术标签:

【中文标题】以编程方式使视图变暗【英文标题】:programmatically darken a View android 【发布时间】:2011-09-28 17:40:29 【问题描述】:

我找到了change the opacity of a View 的方法,但实际上我需要将View 变暗。我最好的办法是在上面放一个透明的黑色矩形,然后慢慢增加矩形的不透明度。

你知道更好的方法吗?

public class Page07AnimationView extends ParentPageAnimationView 
    private final String TAG = this.getClass().getSimpleName();
    private ImageView overlay;
    private int mAlpha = 0;

    public Page07AnimationView(Context context) 
        super(context);
    

    public Page07AnimationView(Context context, AttributeSet attrs) 
        super(context, attrs);
    

    protected void init()
    
        overlay = new ImageView(mContext);
        overlay.setImageResource(R.drawable.black_background);
        overlay.setAlpha(0);
        overlay.setWillNotDraw(false);
        // make the PageAniSurfaceView focusable so it can handle events
        setFocusable(true);
    

    protected void draw_bitmaps(Canvas canvas)
    
        overlay.draw(canvas);
        update_bitmaps();
        invalidate();
    

    public void update_bitmaps()
    
        if(mAlpha < 250)
        
            mAlpha += 10;
            overlay.setAlpha(mAlpha);
        
    

上面的代码并没有达到我的预期。 Page07AnimationView 添加到 FrameLayout 在我需要变暗的视图上。 R.drawable.black_background 指向 787px x 492px 黑色 png 图片。

我添加了overlay.setWillNotDraw(false);,但没有帮助。 我将第一个 setAlpha(0) 更改为 setAlpha(255) 但这没有帮助。 我完全删除了 setAlpha() 调用,但没有帮助。

这种添加PageNNAnimationView 的基本技术一直在绘制Bitmaps,而不是绘制ImageView overlay。 (我会使用 Bitmaps,但它们似乎没有 alpha 组件。)

Edit2:这是上面类的父类:

public class ParentPageAnimationView extends View 
    private final String TAG = this.getClass().getSimpleName();
    protected Context mContext;

    public ParentPageAnimationView(Context context) 
        super(context);
        mContext = context;
        init();
    

    public ParentPageAnimationView(Context context, AttributeSet attrs) 
        super(context, attrs);
        mContext = context;
        init();
    

    protected void init()
    
    

    protected void draw_bitmaps(Canvas canvas)
    
        // will be overridden by child classes
    

    @Override
    protected void onDraw(Canvas canvas) 
        if(this.getVisibility() == View.VISIBLE)
        
            if(canvas != null)
            
                draw_bitmaps(canvas);
            
        
    

    public void update_bitmaps() 
    
        // will be overridden by child classes
    

    public void elementStarted(PageElement _pageElement) 
        // Nothing in parent class
    

    public void elementFinished(PageElement mElement) 
        // Nothing in parent class
    

【问题讨论】:

我已经确认 draw_bitmaps 和 update_bitmaps 被重复调用了。 【参考方案1】:

android 实际上公开了一个可用于使视图变暗的可绘制对象。您可以使用 Overlay 轻松地将其附加到任何视图。

这里有两个扩展函数可以用来使任何视图变暗。

fun View.darken() 
    val darkOverlay = ResourcesCompat.getDrawable(
            resources,
            android.R.drawable.screen_background_dark_transparent,
            context.theme
    )!!.mutate() // We mutate the drawable so we can later implement a fade in/out animation and animate the Drawable's alpha property. Since Drawables share their state we need to mutate otherwise we would impact all instances of this drawable
    darkOverlay.setBounds(0, 0, width, height)
    setTag(R.id.dark_overlay, darkOverlay)
    overlay.add(darkOverlay)


fun View.lighten() 
    (getTag(R.id.dark_overlay) as? Drawable)?.let 
        overlay.remove(it)
        setTag(R.id.dark_overlay, null)
    

确保将 id 添加到 ids.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="dark_overlay" type="id" />
</resources>

如果您要使应用程序的根布局变暗,并且还想使NavigationBar 变暗,您可能需要在styles.xml 的主题中添加以下内容

<style name="BaseTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    <!-- required for api 29 otherwise the system will set a white background color to the NavigationBar to ensure the buttons are visible -->
    <item name="android:enforceNavigationBarContrast">false</item>
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>

【讨论】:

【参考方案2】:

添加到android开发者的答案:

imageView.setColorFilter(Color.rgb(123, 123, 123), android.graphics.PorterDuff.Mode.MULTIPLY);

您可以像这样在任何视图上设置ColorFilter:

GradientDrawable gd = (GradientDrawable) textView.getBackground();
gd.setColor(color); //you can also set BG color to a textview like this
gd.setColorFilter(Color.rgb(123, 123, 123), android.graphics.PorterDuff.Mode.MULTIPLY);

【讨论】:

【参考方案3】:

我会这样做:

view.getBackground().setColorFilter(color, PorterDuff.Mode.DARKEN);

使用带有一些 alpha 的黑色(例如 0x7f000000)进行典型的变暗。

它更简洁,您还可以通过动画或滚动事件使View 变暗。只需将Color.argb(alpha, 0, 0, 0) 设置为颜色并为alpha 设置动画,或者根据滚动偏移量进行更改。

【讨论】:

此方法现已弃用,但您可以使用ColorMatrixColorFilterPorterDuffColorFilter 设置颜色过滤器【参考方案4】:

如果是 ImageView,这是实现它的一种方法:

imageView.setColorFilter(Color.rgb(123, 123, 123), android.graphics.PorterDuff.Mode.MULTIPLY);

【讨论】:

这会使用更多或更少的资源然后设置.setAlpha((float)1.0)(用于sdk 11 及更高版本)或.setAlpha(100)(用于sdk 11 及更低版本)。我问的原因是因为我设置了不透明度来实现这一点,如果我可以调用它并且如果它更兼容那就太好了。 @AaronRussell 我认为如果你使用 setAlpha 会更好,因为它可能是 GPU 优化的。当然,我可能是错的。最好的办法应该是始终使用最新的 API 函数。【参考方案5】:

这就是我最终做到的方式。关键是使用 Paint 并将其 alpha 设置为我想要的任何内容。

public class Page07AnimationView extends ParentPageAnimationView 
    private final String TAG = this.getClass().getSimpleName();
    private Bitmap bitmap;
    private BitmapDrawable drawable;
    private ImageView overlay;
    private int which = -1;
    private long last_time;
    private Page07State state;
    private int mAlpha;
    private int maxAlpha;
    private Paint mPaint;
    private int _alpha_step;
    private int minAlpha;

    public enum Page07State 
        WAITING, DARKENING, DARKENED
    

    public Page07AnimationView(Context context) 
        super(context);
    

    public Page07AnimationView(Context context, AttributeSet attrs) 
        super(context, attrs);
    

    protected void init()
    
        minAlpha = 0;
        mAlpha = minAlpha;
        _alpha_step = 5;
        maxAlpha = 255;
        mPaint = new Paint();
        mPaint.setAlpha(minAlpha);
        state = Page07State.WAITING;
        overlay = new ImageView(mContext);
        overlay.setImageResource(R.drawable.black_background);
        drawable = (BitmapDrawable) overlay.getDrawable();
        bitmap = drawable.getBitmap();
        last_time = 0;
    

    protected void draw_bitmaps(Canvas canvas)
    
        if(state != Page07State.WAITING)
        
            DebugLog.d(TAG, "drawing " + Integer.toString(which));
            canvas.drawBitmap(bitmap, 0, 0, mPaint);
        
        update_bitmaps();
        invalidate();
    

    public void update_bitmaps()
    
        if(state == Page07State.DARKENING)
        
            if(mAlpha < maxAlpha)
            
                if(System.currentTimeMillis() > last_time + 12)
                
                    last_time = System.currentTimeMillis();
                    mAlpha += _alpha_step;
                    mPaint.setAlpha(mAlpha);
                
            
            else
            
                state = Page07State.DARKENED;
            
        
    

    public void runAnimation()
    
        state = Page07State.DARKENING;
    

【讨论】:

【参考方案6】:

您应该在this question 中查看 iPaulPro 的答案。您将需要扩展 ImageView 并覆盖 onDraw() 方法。

根据您要做什么,Alexandru Cristescu 的回答也是有效的,但您应该 调用setFillAter(true) 使动画在完成后持续存在。

【讨论】:

【参考方案7】:

您可以尝试使用这样的 Alpha 动画(可能在矩形上):

    Animation animation = new AlphaAnimation(0.0f, 1.0f);
    animation.setDuration(350);

这会导致矩形在 350 秒内逐渐变得不透明...

【讨论】:

我认为当他说 nicer 时,他的意思是“更合适”,而不是“更可爱”【参考方案8】:

我宁愿以相反的方式进行 - 在视图后面放置一个黑色矩形并设置视图的不透明度。当视图 100% 不透明时,这样可以节省绘制矩形。

【讨论】:

这是个好主意!不过,由于我的布局布局方式,我认为我不得不在“视图”上做一些事情。但是在它们后面有一个动画布局可能会解决另一个问题;谢谢! 在半透明视图后面运行动画时,可能会触发重新绘制整个屏幕。在模拟器的 DevTools 中启用“显示屏幕更新”并查看重绘的内容。

以上是关于以编程方式使视图变暗的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式使十六进制颜色变暗[关闭]

以编程方式使飞镖中的十六进制颜色变亮或变暗

如何使背景视图变暗

有没有办法以编程方式使给定 RGB 值的颜色变暗?

使视图变暗,就像禁用一样

Android M Light and Dark状态栏以编程方式 - 如何使其再次变暗?