问题
I'm attempting to put an ImageView
in a CollapsingToolbarLayout
in which it takes up the full screen on load and as you scroll the content, the 16x9 resolution image width resizes until the image takes up the full width of the screen. At that point, I'd like the image to parallax with a app:layout_collapseParallaxMultiplier
of 0.5
Using this XML Layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="@+id/img_hero"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="@drawable/lake"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.5"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="none"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_scrolling"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
app:layout_anchor="@id/app_bar"
app:layout_anchorGravity="bottom|end"
app:srcCompat="@android:drawable/ic_dialog_email"/>
</android.support.design.widget.CoordinatorLayout>
Accomplishes the following:
Which the following shows what the actual boundaries of the image are:
As I scroll, I would like more of the image width to show as the height of the image shrinks and results in the following:
Once I get to this point, this is where I would like the collapse parallax multiplier of 0.5 to take effect.
I've messed with many different scroll behaviors, tried all of the ImageView
scrollTypes, to no avail. Does anybody know if this is possible and if so, can provide any pointers into what I'm either doing wrong or not doing.
Do I need to create my own custom CoordinatorLayout.Behavior
to accomplish this?
回答1:
You can achieve what you want by tracking vertical offset of AppBarLayout
. It has beautiful method addOnOffsetChangedListener
, so you can scale your image depending on offset of AppBarLayout
.
So, there are three things that you have to do to get it working:
- You need to place your image into
drawable-nodpi
folder, to prevent Android from scaling it for different screen sizes. - Change your
ImageView
's propertyscaleType
tomatrix
- it's needed as we will change matrix of thisImageView
by ourselves. Implement
addOnOffsetChangedListener
for youAppBarLayout
by next way: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's width and height final int dwidth = imageView.getDrawable().getIntrinsicWidth(); final int dheight = imageView.getDrawable().getIntrinsicHeight(); //get view's 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's 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); } } });
What I did here is just get ImageView
's source code to determine bounds when it has centerCrop
scale type and then just calculate the scale and translation of matrix depending on verticalOffset
. If scale value is less than 1.0f then we've just reached the point where our view's aspect ratio is equal to the drawable's aspect ratio, and we don't need to scale more.
Note:
- It would work as you wish, only with the image whose width > height, otherwise its behavior would be the same as
centerCrop
- It would work only if your
parallaxMultiplier
is in between 0 and 1.
How it looks for me:
来源:https://stackoverflow.com/questions/41458682/issue-with-coordinatorlayout-and-imageview-that-adjusts-width-while-scrolling