Ответ 1
Вы можете добиться того, чего хотите, отслеживая вертикальное смещение AppBarLayout
. Он имеет прекрасный метод addOnOffsetChangedListener
, поэтому вы можете масштабировать изображение в зависимости от смещения AppBarLayout
.
Итак, есть три вещи, которые вы должны сделать, чтобы заставить его работать:
- Вам нужно поместить свое изображение в папку
drawable-nodpi
, чтобы предотвратить его масштабирование для разных размеров экрана. - Измените свойство
ImageView
scaleType
наmatrix
- это необходимо, поскольку мы сами изменим матрицу этогоImageView
. -
Внесите
addOnOffsetChangedListener
для васAppBarLayout
следующим образом:final ImageView imageView = (ImageView) findViewById(R.id.img_hero); AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.app_bar); appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { Matrix matrix = new Matrix(imageView.getImageMatrix()); //get image width and height final int dwidth = imageView.getDrawable().getIntrinsicWidth(); final int dheight = imageView.getDrawable().getIntrinsicHeight(); //get view width and height final int vwidth = imageView.getWidth() - imageView.getPaddingLeft() - imageView.getPaddingRight(); int vheight = imageView.getHeight() - imageView.getPaddingTop() - imageView.getPaddingBottom(); float scale; float dx = 0, dy = 0; float parallaxMultiplier = ((CollapsingToolbarLayout.LayoutParams) imageView.getLayoutParams()).getParallaxMultiplier(); //maintain the image aspect ratio depending on offset if (dwidth * vheight > vwidth * dheight) { vheight += (verticalOffset); //calculate view height depending on offset scale = (float) vheight / (float) dheight; //calculate scale dx = (vwidth - dwidth * scale) * 0.5f; //calculate x value of the center point of scaled drawable dy = -verticalOffset * (1 - parallaxMultiplier); //calculate y value by compensating parallaxMultiplier } else { scale = (float) vwidth / (float) dwidth; dy = (vheight - dheight * scale) * 0.5f; } int currentWidth = Math.round(scale * dwidth); //calculate current intrinsic width of the drawable if (vwidth <= currentWidth) { //compare view width and drawable width to decide, should we scale more or not matrix.setScale(scale, scale); matrix.postTranslate(Math.round(dx), Math.round(dy)); imageView.setImageMatrix(matrix); } } });
То, что я здесь сделал, - это просто получить исходный код ImageView
для определения границ, когда он имеет тип шкалы centerCrop
, а затем просто рассчитать масштаб и перевод матрицы в зависимости от verticalOffset
. Если значение шкалы меньше 1.0f, то мы только достигли точки, в которой соотношение сторон изображения равно отношению к коэффициенту масштабируемости, и нам больше не нужно масштабировать.
Примечание
- Он работал бы по вашему желанию только с изображением, ширина которого > высота, иначе его поведение будет таким же, как
centerCrop
- Это будет работать, только если ваш
parallaxMultiplier
находится между 0 и 1.
Как он выглядит для меня: