Как реализовать шаблон "Загрузка изображений" (непрозрачность, экспозиция и насыщенность) из Google new Руководство по дизайну материалов
Кто-нибудь заглянул в реализацию Загрузка изображений из самого последнего руководства по дизайну материалов Google.
Рекомендуется, чтобы "иллюстрации и фотографии могли загружаться и переходить в три этапа с шагом в шахматном порядке". Это непрозрачность, экспозиция и насыщенность:
![enter image description here]()
В настоящее время я использую Volley NetworkImageView (фактически это производный класс).
Я уверен, что это будет какой-то вариант ответа на этот вопрос. Я просто не знаю, какие классы/код использовать для кривых насыщения и анимации, которые описаны.
Ответы
Ответ 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? Если вы в конечном итоге его реализуете, я бы хотел увидеть ваш источник.