Подтвердить что ты не робот

Как реализовать шаблон "Загрузка изображений" (непрозрачность, экспозиция и насыщенность) из Google new Руководство по дизайну материалов

Кто-нибудь заглянул в реализацию Загрузка изображений из самого последнего руководства по дизайну материалов Google.

Рекомендуется, чтобы "иллюстрации и фотографии могли загружаться и переходить в три этапа с шагом в шахматном порядке". Это непрозрачность, экспозиция и насыщенность:

enter image description here

В настоящее время я использую Volley NetworkImageView (фактически это производный класс).

Я уверен, что это будет какой-то вариант ответа на этот вопрос. Я просто не знаю, какие классы/код использовать для кривых насыщения и анимации, которые описаны.

4b9b3361

Ответ 1

Благодаря @mttmllns! Предыдущий ответ.

Поскольку предыдущий ответ показывает пример, написанный на С#, и мне было любопытно, я поместил его в java. Полный пример GitHub

В нем описывается трехэтапный процесс, в котором комбинация непрозрачности, контрастности/яркости и насыщенности используется совместно, чтобы помочь спасти наше бедное зрение пользователей.

Подробнее см. в этой статье.

EDIT:

Смотрите, отличный ответ, предоставленный @DavidCrawford.

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

Ответ 2

Обратите внимание, что этот ответ, как он есть, работает только для Lollipop. Причина этого заключается в том, что свойство colorMatrix недоступно для анимации в классе ColorMatrixColorFilter (он не предоставляет методы getColorMatrix и setColorMatrix). Чтобы увидеть это в действии, попробуйте код, в выводе logcat вы увидите предупреждающее сообщение, подобное этому:

Метод setColorMatrix() с типом класса android.graphics.ColorMatrix не найден в целевом классе класса android.graphics.ColorMatrixColorFilter

Сказав это, я смог заставить это работать над более старыми версиями 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, и поэтому я делаю это в методе overriden 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();
}

Ответ 3

Следуя rnrneverdies отличным ответам, я хотел бы предложить небольшое исправление для этой анимационной логики.

Моя проблема с этой реализацией заключается в том, когда речь идет о png-изображениях с прозрачностью (например, круговые изображения или пользовательские фигуры). Для этих изображений цветной фильтр будет отображать прозрачность изображения как черный, а не просто оставлять их прозрачными.

Проблема с этой строкой:

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

Что здесь происходит, так это то, что цветовая матрица сообщает растровому изображению, что альфа-значение каждого пикселя равно текущей фазе альфы. Это, очевидно, не идеально, поскольку пиксели, которые были уже прозрачными, потеряют свою прозрачность и станут черными.

Чтобы исправить это, вместо применения альфы "аддитивного" альфа-поля в цветовой матрице примените ее в поле "multipicative":

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" (elements[19]) примените его к полю "Am" (elements[18]) и используйте значение 0-1, а не Значение 0-255:

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

Теперь переход будет умножать исходное альфа-значение растрового изображения с альфа-фазой анимации и не заставлять альфа-значение, когда его не должно быть.

Надеюсь, что это поможет

Ответ 4

Просто интересно было то же самое. Я нашел сообщение в блоге, в котором подробно описывается, как это сделать с примером, написанным на Xamarin:

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

Суть для кого-то, пишущего на Java: используйте ColorMatrix и ColorMatrixColorFilter.

В сообщении также упоминается важная оптимизация: использование Lollipop скрытого setColorMatrix() API, чтобы избежать оттока GC и GPU.

Вы еще не видели его в каких-либо приложениях Google? Если вы в конечном итоге его реализуете, я бы хотел увидеть ваш источник.