I've been reading around all day without any success on this.
Basically want to be able to set an ImageView inside a android.support.design.widget.CollapsingToolbarLayout to change it's height depending on the onOffsetChanged change detected so that it will "zoom-out" when collapsed to fit the whole image width and "zoom-in" when expanded to do normal centerCrop behavior.
I tried setting the ImageView height in the onOffsetChanged but that causes other issues assuming due to the CollapsingToolbarLayout is also repositioning it.
Sample functionality I've seen in ParallaxListView project but wish to use the CollapsingToolbarLayout.
Anyone able to give sample code (if it is possible)?
Also seen this project but again similar limitation. Other projects as well.
You can try using android:scaleType="matrix"for the collapsing image's layout definition.
In the code,
store the initial ImageMatrix in a Matrix using matrix.set(imageView.getImageMatrix());
And depending upon the scroll of collapsing toolbar, you can use matrix.postScale() to scale the image and finally set it back to the ImageView using imageView.setImageMatrix(matrix). That can give you the zoom in / out effect.
I managed to do it in the end with the following code for anyone else out there that it may help. The code will fit to width when expanded and fit to height when collapsed. It can be changed to scale (zoom) further in if needed.
Not sure if optimal code is written, suggestions welcome. To measure the bitmap and the view and calculate the min/max scale I use the first call to onOffsetChanged which seems to work fine.
public class MyActivity extends AppCompatActivity implements AppBarLayout.OnOffsetChangedListener {
private float collapsedScale;
private float expandedScale;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity_layout);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setTitle(entry.label);
photoView = (ImageView) findViewById(R.id.photo_image);
AppBarLayout mAppBarLayout = (AppBarLayout) findViewById(R.id.appbar);
mAppBarLayout.addOnOffsetChangedListener(this);
}
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
int maxScroll = appBarLayout.getTotalScrollRange();
float scrollPercent = (float) Math.abs(verticalOffset) / (float) maxScroll;
if (collapsedScale == 0) {
Drawable photo = photoView.getDrawable();
int bitmapWidth = photo.getIntrinsicWidth();
int bitmapHeight = photo.getIntrinsicHeight();
collapsedScale = (float)photoView.getWidth()/(float)bitmapWidth;
expandedScale = (float)photoView.getHeight()/(float)bitmapHeight;
scalePhotoImage(photoView, expandedScale);
} else {
scalePhotoImage(photoView, collapsedScale + (expandedScale - collapsedScale) * (1f - scrollPercent));
}
}
private static void scalePhotoImage(ImageView photoView, float scale) {
Drawable photo = photoView.getDrawable();
int bitmapWidth = photo.getIntrinsicWidth();
int bitmapHeight = photo.getIntrinsicHeight();
float offsetX = (photoView.getWidth() - bitmapWidth) / 2F;
float offsetY = (photoView.getHeight() - bitmapHeight) / 2F;
float centerX = photoView.getWidth() / 2F;
float centerY = photoView.getHeight() / 2F;
Matrix imageMatrix = new Matrix();
imageMatrix.setScale(scale, scale, centerX, centerY);
imageMatrix.preTranslate(offsetX, offsetY);
photoView.setImageMatrix(imageMatrix);
}
}
My 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:background="#color/menu_background_color"
tools:context="style.donkey.android.EntryDetailsActivity">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:elevation="6dp"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:contentScrim="#android:color/transparent">
<ImageView
android:id="#+id/photo_image"
android:layout_width="match_parent"
android:layout_height="300dp"
android:src="#drawable/demo_photo"
android:fitsSystemWindows="true"
android:scaleType="matrix"
app:layout_collapseMode="parallax"/>
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="100dp"
android:theme = "#style/ToolBarStyle"
app:layout_collapseMode="pin">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView 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"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<include layout="#layout/content_layout" />
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
Related
I am making a custom Collapsing Toolbar Layout. The collapsing part is finished, the toolbar has been adjusted accordingly. The only thing that is missing is that I want to change my Toolbars background as the Collapsing Toolbar Layout is collapsing, i.e. gradually increase the opacity of my Toolbars background.
I've seen a lot of answers that seemingly do what I want in Java. Unfortunately, I have no basics (at all) in Java and the one that makes the most sense is here: here. I tried pasting said code to my Android Studio IDE and it doesn't work (it's not really overriding anything). For reference, the code of said post is here:
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
//measuring for alpha
int toolBarHeight = toolbar.getMeasuredHeight();
int appBarHeight = appBarLayout.getMeasuredHeight();
Float f = ((((float) appBarHeight - toolBarHeight) + verticalOffset) / ( (float) appBarHeight - toolBarHeight)) * 255;
fading_backdrop.getBackground().setAlpha(255 - Math.round(f));
}
I similarly want to do that, i.e. I want to be able to listen to the Y-offset of my AppBarLayout to gradually change my Toolbars background.
I have the following activity_xml file (just in case):
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout ...>
<com.google.android.material.appbar.AppBarLayout
... >
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/collapsingToolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/bg_collapsing_toolbar"
app:collapsedTitleTextAppearance="#style/CollapsedCollapsingToolbarText"
app:expandedTitleTextAppearance="#style/ExpandedCollapsingToolbarText"
app:layout_scrollFlags="exitUntilCollapsed|scroll">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/bg_collapsing_toolbar"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.75" />
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="#style/Theme.AppCompat.Light">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
... />
<ImageView
... />
<ImageView
... />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
How do I listen to some AppBarLayout offset changes so that I can gradually change my Toolbars background as the Collapsing Toolbar Layout is collapsing in Kotlin?
Try this.
appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
//measuring for alpha
int toolBarHeight = toolbar.getMeasuredHeight();
int appBarHeight = appBarLayout.getMeasuredHeight();
Float f = ((((float) appBarHeight - toolBarHeight) + verticalOffset) / ( (float) appBarHeight - toolBarHeight)) * 255;
fading_backdrop.getBackground().setAlpha(255 - Math.round(f));
})
I have this layout (code is at the bottom) which contains a CollapsingToolBarLayout at the top and a NestedScrollView at the bottom.
When I scroll up, the collapsing toolbar will start to collapse, then the scroll view will scroll up with the collapsing toolbar at first and then goes behind the collapsed tool bar.
I want to have some animations (image slides left when scrolling up and slides back when scrolling down) in the collapsing toolbar. The issue now is: sometimes, when I scroll up, the image doesn't slide left. When it slid left, and I scroll down, it doesn't slide back.
I trigger these animations through onOffsetChanged for the AppBarLayout and OnTouchListener for the NestedScrollView.
// People image slide left when user scrolls up on the scroll view
mScrollView.setOnTouchListener(scrollViewTouchListener);
// People image slide back when app bar is almost expanded
mAppBar.addOnOffsetChangedListener(appBarOffsetChangedListener);
// OnOffsetChangedListener for the AppBarLayout
private AppBarLayout.OnOffsetChangedListener appBarOffsetChangedListener = new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int offset) {
// If the app bar is almost expanded and people image slided left, make it slide back
if ((offset > -20 || offset == 0) && mPeopleSlidedLeft) {
mPeopleImage.animate().setDuration(animationTime)
.translationX(originalPeoplePosition[0]);
mPeopleSlidedLeft = false;
}
}
};
// Touch listener for the scroll view
private View.OnTouchListener scrollViewTouchListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
float y = event.getY();
if (event.getAction() == MotionEvent.ACTION_MOVE) {
float dy = y - mPreviousY;
// if user scrolls up and people image hasn't slided left,
if (dy < -1 && mPeopleSlidedLeft == false) {
DisplayMetrics dm = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
int xDest = dm.widthPixels / 2;
xDest += mPeopleImage.getMeasuredWidth() / 2;
mPeopleImage.animate().setDuration(animationTime)
.translationX(originalPeoplePosition[0] - xDest);
}
}
mPeopleSlidedLeft = true;
mPreviousY = y;
return false;
}
};
Just note that the scrollview's setOnScrollChangeListener won't work as it's not triggered when the toolbar is collapsing.
A simplified version of the layout is below:
<?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.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:elevation="0dp">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/collapsing_toolbar_margin"
android:fitsSystemWindows="true"
android:minHeight="120dp"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<LinearLayout
android:id="#+id/backdrop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:fitsSystemWindows="true"
android:orientation="vertical"
app:layout_collapseMode="parallax">
</LinearLayout>
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="#dimen/toolbar_height"
android:layout_gravity="center_horizontal"
app:contentInsetEnd="16dp"
app:contentInsetStart="16dp"
app:elevation="0dp"
app:layout_collapseMode="pin"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:background="#color/white"
android:orientation="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.v4.widget.NestedScrollView
android:id="#+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
<include
layout="#layout/notification"
android:layout_width="match_parent"
android:layout_height="#dimen/active_inactive_time_height"
android:layout_gravity="bottom"
app:layout_anchorGravity="bottom|right"
android:layout_marginBottom="#dimen/bottom_navigation_bar_offset" />
</android.support.design.widget.CoordinatorLayout>
Can someone please have a look? I will really appreciate it!
I'm not sure why you're using a touch listener on the NestedScrollView, if I understand correctly you want there to be 2 states:
Toolbar is expanded and people image is visible
Toolbar is collapsed and people image is hidden
And the transition between these 2 states should be to slide the people image off the left of the screen?
This should be achievable with the AppBarLayout.OnOffsetChangedListener alone, and you can use the change of offset to "animate" the view moving instead of setting up trigger points which can result in a much smoother implementation.
Something like:
private AppBarLayout.OnOffsetChangedListener appBarOffsetChangedListener = new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
float fraction = ((float) Math.abs(verticalOffset)) / appBarLayout.getTotalScrollRange();
int peopleRange = mPeopleImage.getRight();
mPeopleImage.setTranslationX(fraction * peopleRange * -1);
}
};
I've added some configuration of the timing and speed of the slid. In this case it waits until the header is collapsed 25% before sliding and the image moves left twice as fast. You could play with these numbers to get what you're looking for.
private AppBarLayout.OnOffsetChangedListener appBarOffsetChangedListener = new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
float fraction = ((float) Math.abs(verticalOffset)) / appBarLayout.getTotalScrollRange();
int peopleRange = mPeopleImage.getRight();
float delay = 0.25f;
float speed = 2f;
fraction = Math.max(fraction - delay, 0f) * speed;
mPeopleImage.setTranslationX(fraction * peopleRange * -1);
}
};
I am trying to implement auto-hiding feature for my toolbar using CoordinateLayout. But I also want to tweaks it a bit, so that the hide/show only works after I scroll past my imageview.
I am currently able to "turn on/off" the hide/show availability for the toolbar via AppBarLayout.LayoutParams. So right now it won't hide the toolbar if I scroll within the imageview's height and will hide if I scroll pass the imageview. The only problem is, if I scroll the layout very fast and instantly pull my finger before it pass the imageview's height the toolbar won't hide. In my opinion it is because the scrolling listener's function is called before the parameter of the toolbar's show/hide is changed to enable.
Here's the code:
ArticleActivity.java
public class ArticleActivity extends AppCompatActivity {
private Toolbar toolbar;
private ImageView imageView;
private NestedScrollView scrollView;
private Matrix matrix;
private int imageHeight = 0;
private float scale = 0;
private boolean hideable = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_article);
imageView = (ImageView) findViewById(R.id.imageView);
scrollView = (NestedScrollView) findViewById(R.id.scrollView);
toolbar = (Toolbar) findViewById(R.id.toolbar);
matrix = new Matrix();
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
scale = (float) displayMetrics.widthPixels / ((float) imageView.getDrawable().getIntrinsicWidth());
matrix.postScale(scale, scale);
imageView.setImageMatrix(matrix);
if(imageView.getViewTreeObserver().isAlive()) {
imageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
imageView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
imageHeight = imageView.getHeight();
}
});
}
if(scrollView.getViewTreeObserver().isAlive()) {
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
int scrollY = scrollView.getScrollY();
if(scrollY <= imageHeight) {
matrix.setTranslate(0, scrollY / 4);
matrix.postScale(scale, scale);
imageView.setImageMatrix(matrix);
if(hideable) {
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
params.setScrollFlags(0);
toolbar.setLayoutParams(params);
hideable = false;
}
} else {
if(!hideable) {
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
// 1 = scroll, 4 = enterAlways, 16 = snap
params.setScrollFlags(21);
toolbar.setLayoutParams(params);
hideable = true;
}
}
}
});
}
}}
activity_article.xml:
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="matrix"
android:src="#drawable/download"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/imageView"
android:text="What is Lorem Ipsum?"/>
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
What should I do to fix this? Or is there another way to achieve this? Thank you
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?
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 property scaleType to matrix - it's needed as we will change matrix of this ImageView by ourselves.
Implement addOnOffsetChangedListener for you AppBarLayout 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:
inside of CollapsingToolbarLayout imageview and i need setAlpha(float) When that scroll up and down:
this is method for get Offset and calculate float by offset:
AppBarLayout.OnOffsetChangedListener:
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
float offsetAlpha = (float) (verticalOffset / appBarLayout.getTotalScrollRange());
imageView.setAlpha(offsetAlpha);
}
xml layout:
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsingToolbarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="50dp"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:contentScrim="#android:color/transparent">
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax" />
</android.support.design.widget.CollapsingToolbarLayout>
but setAlpha does not work. why?
Your calculation either gave 0.0 or 1.0.
I tried calculating the offset by getting the fraction of the complete scrollarea.
It's a start and open for improvement.
appbar.addOnOffsetChangedListener(new OnOffsetChangedListener() {
#Override
public void onOffsetChanged(final AppBarLayout appBarLayout, final int verticalOffset) {
float offsetAlpha = (appBarLayout.getY() / appbar.getTotalScrollRange());
imageView.setAlpha( 1 - (offsetAlpha * -1));
}
})
I know it's a very old question and there is an accepted answer but I figured out a better way to do it as Tim solution does not start from 0.0 to 1.0
override fun onOffsetChanged(appBarLayout: AppBarLayout, verticalOffset: Int) {
val offsetAlpha =
1F - ((appBarLayout.totalScrollRange + verticalOffset).toFloat() / appBarLayout.totalScrollRange.toFloat())
imageView.setAlpha(offsetAlpha);
}
The imageView will totally disappear when AppToolbarLayout fully expanded and if you want to reverse this just remove 1F - from offsetAlpha