如何实施"加载图片" Google的新材料设计指南中的图案(不透明度,曝光度和饱和度)

时间:2014-12-03 01:16:11

标签: android material-design

是否有人考虑过使用Google最新的Material Design指南实施Loading images模式。

这是一种推荐的方式,插图和照片可能会在交错的持续时间内分三个阶段加载和转换#34;那些是不透明度,曝光度和饱和度:

enter image description here

我目前正在使用Volley NetworkImageView(实际上是一个派生类)。

我确定它必须是the answer to this question的某种变体。我不确定哪些类/代码可用于描述的饱和度和动画曲线。

4 个答案:

答案 0 :(得分:10)

感谢@mttmllns!上一个答案。

由于上一个答案显示了一个用C#编写的示例,我很好奇,我把它移植到java。 Complete GitHub Example

  

它概述了一个3个步骤的过程,其中不透明度,对比度/亮度和饱和度的组合一起用于帮助挽救我们的不良用户视力。

有关详细说明,请阅读this article

编辑:

请参阅@DavidCrawford提供的优秀answer

BTW:我修复了链接的GitHubProject,以支持前Lollipop设备。 (自API级别11以来)

守则

AlphaSatColorMatrixEvaluator.java

import android.animation.TypeEvaluator;
import android.graphics.ColorMatrix;

public class AlphaSatColorMatrixEvaluator implements TypeEvaluator {
    private ColorMatrix colorMatrix;
    float[] elements = new float[20];

    public AlphaSatColorMatrixEvaluator() {
        colorMatrix = new ColorMatrix ();
    }

    public ColorMatrix getColorMatrix() {
        return colorMatrix;
    }

    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        // There are 3 phases so we multiply fraction by that amount
        float phase = fraction * 3;

        // Compute the alpha change over period [0, 2]
        float alpha = Math.min(phase, 2f) / 2f;
        // elements [19] = (float)Math.round(alpha * 255);
        elements [18] = alpha;

        // We substract to make the picture look darker, it will automatically clamp
        // This is spread over period [0, 2.5]
        final int MaxBlacker = 100;
        float blackening = (float)Math.round((1 - Math.min(phase, 2.5f) / 2.5f) * MaxBlacker);
        elements [4] = elements [9] = elements [14] = -blackening;

        // Finally we desaturate over [0, 3], taken from ColorMatrix.SetSaturation
        float invSat = 1 - Math.max(0.2f, fraction);
        float R = 0.213f * invSat;
        float G = 0.715f * invSat;
        float B = 0.072f * invSat;

        elements[0] = R + fraction; elements[1] = G;            elements[2] = B;
        elements[5] = R;            elements[6] = G + fraction; elements[7] = B;
        elements[10] = R;           elements[11] = G;           elements[12] = B + fraction;

        colorMatrix.set(elements);
        return colorMatrix;
    }
}

以下是设置方法:

ImageView imageView = (ImageView)findViewById(R.id.imageView);
final BitmapDrawable drawable = (BitmapDrawable) getResources().getDrawable(R.drawable.image);
imageView.setImageDrawable(drawable);
AlphaSatColorMatrixEvaluator evaluator = new AlphaSatColorMatrixEvaluator ();
final ColorMatrixColorFilter filter = new ColorMatrixColorFilter(evaluator.getColorMatrix());
drawable.setColorFilter(filter);

ObjectAnimator animator = ObjectAnimator.ofObject(filter, "colorMatrix", evaluator, evaluator.getColorMatrix());

animator.addUpdateListener( new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        drawable.setColorFilter (filter);
    }
});
animator.setDuration(1500);
animator.start();

结果如下:

enter image description here

答案 1 :(得分:8)

请注意,this answer目前仅适用于棒棒糖。原因是因为colorMatrix属性不可用于ColorMatrixColorFilter类的动画(它没有提供getColorMatrix和setColorMatrix方法)。要查看此操作,请尝试代码,在logcat输出中,您应该看到如下警告消息:

方法setColorMatrix(),在目标类类android.graphics.ColorMatrixColorFilter

上找不到类型类android.graphics.ColorMatrix

话虽如此,通过创建以下类(不是最好的名字,我知道),我能够让它在旧的Android版本(pre-Lollipop)上工作

private class AnimateColorMatrixColorFilter {
    private ColorMatrixColorFilter mFilter;
    private ColorMatrix mMatrix;

    public AnimateColorMatrixColorFilter(ColorMatrix matrix) {
        setColorMatrix(matrix);
    }

    public ColorMatrixColorFilter getColorFilter() {
        return mFilter;
    }

    public void setColorMatrix(ColorMatrix matrix) {
        mMatrix = matrix;
        mFilter = new ColorMatrixColorFilter(matrix);
    }

    public ColorMatrix getColorMatrix() {
        return mMatrix;
    }
}

然后,设置代码将如下所示。请注意,我有这个"设置"在ImageView的派生类中,所以我在覆盖方法setImageBitmap中执行此操作。

@Override
public void setImageBitmap(Bitmap bm) {
    final Drawable drawable = new BitmapDrawable(getContext().getResources(), bm);
    setImageDrawable(drawable);

    AlphaSatColorMatrixEvaluator evaluator = new AlphaSatColorMatrixEvaluator();
    final AnimateColorMatrixColorFilter filter = new AnimateColorMatrixColorFilter(evaluator.getColorMatrix());
    drawable.setColorFilter(filter.getColorFilter());

    ObjectAnimator animator = ObjectAnimator.ofObject(filter, "colorMatrix", evaluator, evaluator.getColorMatrix());

    animator.addUpdateListener( new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            drawable.setColorFilter(filter.getColorFilter());
        }
    });
    animator.setDuration(1500);
    animator.start();
}

答案 2 :(得分:2)

关注rnrneverdies优秀答案,我想为此动画逻辑提供一个小修补程序。

这个实现的问题在于具有透明度的png图像(例如,圆形图像或自定义形状)。对于这些图像,滤色器会将图像的透明度绘制为黑色,而不是将它们保持透明。

问题在于这一行:

elements [19] = (float)Math.round(alpha * 255);

这里发生的是颜色矩阵告诉位图每个像素的alpha值等于alpha的当前相位。这显然不是完美的,因为已经透明的像素将失去透明度并显示为黑色。

要解决此问题,请不要应用"添加剂"的alpha。颜色矩阵中的alpha字段,将其应用于"乘法"字段:

Rm | 0  | 0  | 0  | Ra
0  | Gm | 0  | 0  | Ga
0  | 0  | Bm | 0  | Ba
0  | 0  | 0  | Am | Aa

Xm = multiplicative field
Xa = additive field

所以不要在" Aa"上应用alpha值。字段(elements[19]),将其应用于" Am"字段(elements[18]),并使用0-1值而不是0-255值:

//elements [19] = (float)Math.round(alpha * 255);
elements [18] = alpha;

现在转换会将位图的原始alpha值与动画的alpha阶段相乘,并且在不应该为某个时不强制使用alpha值。

希望这有帮助

答案 3 :(得分:1)

只是想知道同样的事情。我发现了一篇博文,详细介绍了如何使用Xamarin编写的示例:

http://blog.neteril.org/blog/2014/11/23/android-material-image-loading/

使用Java编写的人的要点:使用ColorMatrixColorMatrixColorFilter

该帖子还提到了一项重要的优化:使用Lollipop隐藏setColorMatrix() API来避免GC和GPU流失。

您是否在任何Google应用中看到过它?如果你最终实现它,我很乐意看到你的来源。