I am following this popular link for cordinator behaviour, following this post .
I wanted a desired behavior that image should be floated to right side instead of left and for this, I modified
AvatarImageBehavior.java -> maybeInitProperties() method ->
as following :
if (mFinalXPosition == 0)
mFinalXPosition= getScreenWidth()-70;
Now I wish the toolbar to be fixed at top, and only image to move and stick to it.
As per my understanding, only Behavior file is responsible for this transition.
I tried too many things, but not getting and proper approach / call back to proceed.
Any solution/ approach/ different sample is most welcome.
So, the first thing you should do is to tweak the layout file - make Toolbar
fixed at top by removing its layout_anchor
attribute.
<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"
tools:ignore="RtlHardcoded"
>
<android.support.design.widget.AppBarLayout
android:id="@+id/main.appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/main.collapsing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
>
<ImageView
android:id="@+id/main.imageview.placeholder"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="centerCrop"
android:src="@drawable/quila2"
android:tint="#11000000"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.9"
/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
app:behavior_overlapTop="24dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
>
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardElevation="8dp"
app:contentPadding="16dp"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:lineSpacingExtra="8dp"
android:text="@string/lorem"
android:textSize="18sp"
/>
</android.support.v7.widget.CardView>
</android.support.v4.widget.NestedScrollView>
<android.support.v7.widget.Toolbar
android:id="@+id/main.toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/primary"
app:theme="@style/ThemeOverlay.AppCompat.Dark"
app:title="">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="@+id/main.textview.title"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:gravity="center_vertical"
android:text="@string/quila_name2"
android:textColor="@android:color/white"
android:textSize="20sp"/>
</LinearLayout>
</android.support.v7.widget.Toolbar>
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="@dimen/image_width"
android:layout_height="@dimen/image_width"
android:layout_gravity="center_horizontal"
android:src="@drawable/quila"
app:border_color="@android:color/white"
app:border_width="2dp"
app:finalHeight="@dimen/image_final_width"
app:layout_behavior="saulmm.myapplication.AvatarImageBehavior"
/>
</android.support.design.widget.CoordinatorLayout>
Note, I've also removed main.framelayout.title
section, as I consider it as a part of a Toolbar
as well. And I've also removed onOffsetChanged()
and all relative to it methods in MainActivity
, and made our title of Toolbar
always visible.
Secondly, of course, you should make changes in the AvatarImageBehavior
class. The main thing here is that now your ImageView
is dependent on NestedScrollView
instead of Toolbar
. But since we're not dependent on Toolbar
anymore, we still need it to define the mFinalYPosition
, so I've added the method to find the Toolbar
as well. Here is the behavior:
public class AvatarImageBehavior extends CoordinatorLayout.Behavior<CircleImageView> {
private final static float MIN_AVATAR_PERCENTAGE_SIZE = 0.3f;
private final static int EXTRA_FINAL_AVATAR_PADDING = 80;
private final static String TAG = "behavior";
private Context mContext;
private float mCustomFinalYPosition;
private float mCustomStartXPosition;
private float mCustomStartToolbarPosition;
private float mCustomStartHeight;
private float mCustomFinalHeight;
private float mAvatarMaxSize;
private float mStartPosition;
private int mStartXPosition;
private float mStartToolbarPosition;
private int mStartYPosition;
private int mFinalYPosition;
private int mStartHeight;
private int mFinalXPosition;
private float mChangeBehaviorPoint;
public AvatarImageBehavior(Context context, AttributeSet attrs) {
mContext = context;
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AvatarImageBehavior);
mCustomFinalYPosition = a.getDimension(R.styleable.AvatarImageBehavior_finalYPosition, 0);
mCustomStartXPosition = a.getDimension(R.styleable.AvatarImageBehavior_startXPosition, 0);
mCustomStartToolbarPosition = a.getDimension(R.styleable.AvatarImageBehavior_startToolbarPosition, 0);
mCustomStartHeight = a.getDimension(R.styleable.AvatarImageBehavior_startHeight, 0);
mCustomFinalHeight = a.getDimension(R.styleable.AvatarImageBehavior_finalHeight, 0);
a.recycle();
}
init();
}
private void init() {
bindDimensions();
}
private void bindDimensions() {
mAvatarMaxSize = mContext.getResources().getDimension(R.dimen.image_width);
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, CircleImageView child, View dependency) {
return dependency instanceof NestedScrollView;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, CircleImageView child, View dependency) {
maybeInitProperties(parent, child, dependency);
final int maxScrollDistance = (int) (mStartToolbarPosition);
float expandedPercentageFactor = dependency.getY() / maxScrollDistance;
if (expandedPercentageFactor < mChangeBehaviorPoint) {
float heightFactor = (mChangeBehaviorPoint - expandedPercentageFactor) / mChangeBehaviorPoint;
float distanceXToSubtract = ((mStartXPosition - mFinalXPosition)
* heightFactor) + (child.getHeight()/2);
float distanceYToSubtract = ((mStartYPosition - mFinalYPosition)
* (1f - expandedPercentageFactor)) + (child.getHeight()/2);
child.setX(mStartXPosition - distanceXToSubtract);
child.setY(mStartYPosition - distanceYToSubtract);
float heightToSubtract = ((mStartHeight - mCustomFinalHeight) * heightFactor);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
lp.width = (int) (mStartHeight - heightToSubtract);
lp.height = (int) (mStartHeight - heightToSubtract);
child.setLayoutParams(lp);
} else {
float distanceYToSubtract = ((mStartYPosition - mFinalYPosition)
* (1f - expandedPercentageFactor)) + (mStartHeight/2);
child.setX(mStartXPosition - child.getWidth()/2);
child.setY(mStartYPosition - distanceYToSubtract);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
lp.width = (int) (mStartHeight);
lp.height = (int) (mStartHeight);
child.setLayoutParams(lp);
}
return true;
}
private void maybeInitProperties(CoordinatorLayout parent, CircleImageView child, View dependency) {
if (mStartYPosition == 0)
mStartYPosition = (int) (dependency.getY());
View toolbar = tryFindToolbarInLayout(parent);
if (mFinalYPosition == 0 && toolbar != null) {
mFinalYPosition = (toolbar.getHeight() / 2);
}
if (mStartHeight == 0)
mStartHeight = child.getHeight();
if (mStartXPosition == 0)
mStartXPosition = (int) (child.getX() + (child.getWidth() / 2));
if (mFinalXPosition == 0)
mFinalXPosition = dependency.getContext().getResources().getDisplayMetrics().widthPixels - mContext.getResources().getDimensionPixelOffset(R.dimen.abc_action_bar_content_inset_material)
- ((int) mCustomFinalHeight / 2);
if (mStartToolbarPosition == 0)
mStartToolbarPosition = dependency.getY();
if (mChangeBehaviorPoint == 0 && toolbar != null) {
mChangeBehaviorPoint = (child.getHeight() - mCustomFinalHeight) / (mStartYPosition - mFinalYPosition - toolbar.getHeight());
}
}
private View tryFindToolbarInLayout(CoordinatorLayout parent) {
for (int i = 0; i < parent.getChildCount(); i++) {
View child = parent.getChildAt(i);
if (child instanceof Toolbar)
return child;
}
return null;
}
public int getStatusBarHeight() {
int result = 0;
int resourceId = mContext.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = mContext.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
}
This is what I managed to do: