I try to create a collapsing layout on scroll, but I encounter an issue with my avatar, indeed when the CircleImageView is inside my AppBarLayout, nothing happens, I need to put it below my ToolbarLayout, here is my xml to be clearer :
<?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:id="#+id/coordinator_layout_root"
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.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">
<RelativeLayout
android:id="#+id/relative_layout_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="#dimen/activity_vertical_margin">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/circle_image_view_avatar"
android:layout_width="#dimen/menu_size_avatar"
android:layout_height="#dimen/menu_size_avatar"
android:layout_gravity="center"
android:layout_centerHorizontal="true"
android:layout_marginTop="#dimen/profile_margin_top_avatar"
android:src="#drawable/avatar_6"
app:civ_border_color="#color/white"
app:civ_border_width="#dimen/avatar_border_width"
app:finalHeight="#dimen/image_final_width"
app:layout_collapseMode="parallax"
app:layout_behavior="com.example.AvatarImageBehavior"
app:startHeight="2dp"
app:startToolbarPosition="2dp"
app:startXPosition="2dp" />
<FrameLayout
android:id="#+id/frame_layout_ranking"
android:layout_width="47dp"
android:layout_height="47dp"
android:layout_alignLeft="#id/circle_image_view_avatar"
android:layout_alignStart="#id/circle_image_view_avatar"
android:layout_alignTop="#id/circle_image_view_avatar">
<ImageView
android:layout_width="#dimen/profile_button_ranking_trophies_size"
android:layout_height="#dimen/profile_button_ranking_trophies_size"
android:background="#drawable/circle_white"
android:scaleType="centerInside"
android:src="#drawable/ic_classement" />
</FrameLayout>
<FrameLayout
android:id="#+id/frame_layout_trophies"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignEnd="#id/circle_image_view_avatar"
android:layout_alignRight="#id/circle_image_view_avatar"
android:layout_alignTop="#id/circle_image_view_avatar">
<ImageView
android:layout_width="#dimen/profile_button_ranking_trophies_size"
android:layout_height="#dimen/profile_button_ranking_trophies_size"
android:background="#drawable/circle_white"
android:scaleType="centerInside"
android:src="#drawable/ic_trophees" />
</FrameLayout>
<FrameLayout
android:id="#+id/frame_layout_level"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/circle_image_view_avatar"
android:layout_centerHorizontal="true">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/circle_image_view_level"
android:layout_width="#dimen/menu_size_level"
android:layout_height="#dimen/menu_size_level"
app:civ_border_color="#color/white"
app:civ_border_width="#dimen/avatar_border_width" />
</FrameLayout>
<TextView
android:id="#+id/text_view_pseudo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/frame_layout_level"
android:layout_centerHorizontal="true"
android:maxLines="2"
android:textAllCaps="true"
android:textColor="#color/white"
android:textSize="#dimen/font_32" />
</RelativeLayout>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<!-- Content -->
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:scrollbars="none">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingTop="#dimen/activity_vertical_margin">
....
</LinearLayout>
</android.support.v7.widget.CardView>
</android.support.v4.widget.NestedScrollView>
<!-- Final toolbar -->
<android.support.v7.widget.Toolbar
android:id="#+id/main.toolbar"
android:layout_width="match_parent"
android:layout_height="54dp"
android:background="#5025A5FF"
app:layout_anchor="#id/text_view_pseudo"
app:layout_anchorGravity="center_vertical"
app:theme="#style/ThemeOverlay.AppCompat.Dark"
app:title="">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:maxLines="2"
android:textAllCaps="true"
android:text="Pseudo"
android:textColor="#color/white"
android:textSize="#dimen/font_18" />
</LinearLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CoordinatorLayout>
Here is the code of my AvatarImageBehavior class :
import android.content.Context;
import android.content.res.TypedArray;
import android.support.design.widget.CoordinatorLayout;
import android.support.v7.widget.Toolbar;
import android.util.AttributeSet;
import android.view.View;
import com.example.R;
import de.hdodenhof.circleimageview.CircleImageView;
#SuppressWarnings("unused")
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 mCustomFinalXPosition;
private float mCustomFinalYPosition;
private float mCustomStartXPosition;
private float mCustomStartToolbarPosition;
private float mCustomStartHeight;
private float mCustomFinalHeight;
private float mAvatarMaxSize;
private float mFinalLeftAvatarPadding;
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);
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();
mFinalLeftAvatarPadding = context.getResources().getDimension(R.dimen.activity_vertical_little_margin);
}
private void init() {
bindDimensions();
}
private void bindDimensions() {
mAvatarMaxSize = mContext.getResources().getDimension(R.dimen.game_answer_bonus);
}
#Override
public boolean layoutDependsOn(CoordinatorLayout parent, CircleImageView child, View dependency) {
return dependency instanceof Toolbar;
}
#Override
public boolean onDependentViewChanged(CoordinatorLayout parent, CircleImageView child, View dependency) {
maybeInitProperties(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(CircleImageView child, View dependency) {
if (mStartYPosition == 0) {
// mStartYPosition = (int) (dependency.getY());
mStartYPosition = 185;
}
if (mFinalYPosition == 0)
mFinalYPosition = (dependency.getHeight() /2);
if (mStartHeight == 0)
mStartHeight = child.getHeight();
if (mStartXPosition == 0)
mStartXPosition = (int) (child.getX() + (child.getWidth() / 2));
if (mFinalXPosition == 0) {
// mFinalXPosition = mContext.getResources().getDimensionPixelOffset(R.dimen.abc_action_bar_content_inset_material) + ((int) mCustomFinalHeight / 2);
mFinalXPosition = (int) (dependency.getWidth() - mContext.getResources().getDimension(R.dimen.image_final_width) + mContext.getResources().getDimension(R.dimen.profile_toolbar_margin_right));
}
if (mStartToolbarPosition == 0)
mStartToolbarPosition = dependency.getY();
if (mChangeBehaviorPoint == 0) {
mChangeBehaviorPoint = (child.getHeight() - mCustomFinalHeight) / (2f * (mStartYPosition - mFinalYPosition));
}
}
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;
}
}
Do you see why, my CircleImageView react only when it's outside the AppBarLayout. I need it to be inside because, my FrameLayout are views over the CircleImageView (an avatar). I begin with CoordinatorLayout so maybe I miss something.
Regards.
Related
I am trying to implement behaviour which is shown below (on pictures), so I need to stretch all content below AppBarLayout. I've already achieved it somehow by implementing custom CoordinatorLayout Behaviour but that solution have some issues with views recycling inside RecyclerView and overall performance. Is there easier solution to achieve what i want?
public class TestBehaviour48Margin extends CoordinatorLayout.Behavior {
public TestBehaviour48Margin() {
}
public TestBehaviour48Margin(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean layoutDependsOn(#NonNull CoordinatorLayout parent, #NonNull View child, #NonNull View dependency) {
return dependency instanceof AppBarLayout;
}
#Override
public boolean onDependentViewChanged(#NonNull CoordinatorLayout parent, #NonNull View child, #NonNull View dependency) {
AppBarLayout appBarLayout = (AppBarLayout) dependency;
val toolbar = appBarLayout.findViewById(R.id.toolbar);
int range = appBarLayout.getTotalScrollRange();
int totalHeight = parent.getHeight();
int appBarHeight = appBarLayout.getHeight();
int toolbarHeight = toolbar.getHeight();
int initialHeight = totalHeight - appBarHeight;
int finalHeight = totalHeight - toolbarHeight;
int differenceHeight = finalHeight - initialHeight;
float factor = -appBarLayout.getY() / range;
val layoutParams = child.getLayoutParams();
int lastHeight = layoutParams.height;
layoutParams.height = (int) (initialHeight + (differenceHeight * factor)) + LayoutUtils.dpToPx(parent.getContext(), 48);
if(lastHeight != layoutParams.height){
child.setLayoutParams(layoutParams);
}
return true;
}
}
<CoordinatorLayout ... (some content)
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="48dp"
android:layout_gravity="bottom"
app:layout_behavior=".custom_views.TestBehaviour48Margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/custom_pink"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:nestedScrollingEnabled="false"
android:id="#+id/rv_strength_items"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#color/grey_B" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#color/custom_blue_light" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_gravity="bottom"
android:background="#color/custom_green"
bind:layout_anchor="#id/scroll"
bind:layout_anchorGravity="bottom" />
</LinearLayout>
</FrameLayout>
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorSurfaceNight"
android:visibility="#{viewmodel.views.mainLayoutVisibility}"
app:elevation="0dp"
app:layout_behavior=".fragments.training.main_training.view_fold.BlockableAppBarLayoutBehaviour">
... rest of code
I am trying to create a simple ball and stick game in android and have the following xml file for android.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
tools:context=".BallActivity">
<learn.com.application.BallView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/ball"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Left"
android:onClick="moveleft"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Right"
android:onClick="moveright"/>
</LinearLayout>
</LinearLayout>
The LinearLayout containing the buttons is not visible as the BallView is match_parent. But if i declare height of BallView as wrap_content It does not work. How can i show the left and right buttons on the bottom. What else can i use for moving the stick left or right.
Code for BallView
public class BallView extends android.support.v7.widget.AppCompatImageView {
private Context mContext;
int x = -1;
int y = -1;
boolean first=true;
private int xVelocity = 10;
private int yVelocity = 5;
private Handler h;
public static int FRAME_RATE = 50;
public static int stickx=0,sticky=0;
public static int width=0;
public static int height=0;
boolean gameover=false;
public BallView(Context context,AttributeSet s) {
super(context,s);
mContext=context;
h=new Handler();
}
private Runnable r=new Runnable() {
#Override
public void run() {
invalidate();
}
};
#Override
protected void onDraw(Canvas canvas) {
if(first) {
stickx = getWidth() / 2 - 40;
sticky = getHeight() - 60;
width = getWidth();
height = getHeight();
first=false;
}
Bitmap bmp= BitmapFactory.decodeResource(mContext.getResources(),R.drawable.ball1);
if(x<0 && y<0)
{
x=getWidth()/2;
y=getHeight()/2;
}
else {
x += xVelocity;
y += yVelocity;
if (x + bmp.getWidth() > getWidth() || (x < 0))
xVelocity = xVelocity * -1;
if (y < 0)
yVelocity = yVelocity * -1;
if (y + bmp.getHeight() >= sticky) {
if (x + bmp.getWidth() > stickx && x + bmp.getWidth() < (stickx + 180)) {
yVelocity = yVelocity * -1;
Log.v("ball","collision");
}
else {
Log.v("ball", "game over");
gameover=true;
}
}
}
RectF rr=new RectF();
int right=stickx+180;
int bottom=sticky+30;
rr.set(stickx,sticky,right,bottom);
Paint p=new Paint();
canvas.drawRoundRect(rr,5,5,p);
canvas.drawBitmap(bmp,x,y,null);
if(!gameover)
h.postDelayed(r,FRAME_RATE);
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:context=".BallActivity">
<learn.com.application.BallView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/tablerow"
android:id="#+id/ball"/>
<TableRow
android:id="#+id/tablerow"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Left"
android:onClick="moveleft"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Right"
android:onClick="moveright"/>
</TableRow>
</RelativeLayout>
Instead of using LinearLayout, I would prefer to use RelativeLayout and TableRow as shown
So, situation is this:
I need to implement AppBar scroll behaviour in my main activity, but, I already have CoordinatorLayout and AppBarLayout in my fragment with the same scroll behaviour.
Here is the xml from both of the layouts:
activity_main:
<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:background="#EBEDEC">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/toolbar_open_nav"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:src="#drawable/filter_icon" />
<RelativeLayout
android:id="#+id/main_activity_images_relative"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/toolbar_fencity_image"
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_margin="#dimen/layout_padding"
android:src="#drawable/toolbarimg"
android:visibility="gone" />
</RelativeLayout>
</RelativeLayout>
</android.support.v7.widget.Toolbar>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#android:color/transparent" />
<com.bitage.carlo.fencity.ui.view.BottomMenuView
android:id="#+id/bottom_menu"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</LinearLayout>
</RelativeLayout>
and a fragment xml:
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:id="#+id/novita_app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="#+id/novita_search_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/background"
app:layout_scrollFlags="scroll|enterAlways|snap">
<EditText
android:id="#+id/search_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/layout_padding"
android:background="#null"
android:hint="#string/search"
android:imeOptions="actionDone"
android:paddingEnd="#dimen/layout_padding"
android:paddingLeft="#dimen/padding_start"
android:paddingRight="#dimen/layout_padding"
android:paddingStart="#dimen/padding_start"
android:singleLine="true" />
<ImageView
android:id="#+id/search_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="#dimen/layout_padding"
android:layout_marginStart="#dimen/layout_padding"
android:src="#drawable/ic_search" />
</RelativeLayout>
</android.support.design.widget.AppBarLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="#+id/places_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#android:color/transparent"
android:src="#drawable/nav_shadow" />
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
Now, I need this to stay the same if possible, just somehow to add the scroll behavior app:layout_scrollFlags="scroll|enterAlways|snap" on toolbar only in this fragment, while search from the fragment still has the same behaviour.
How can I achieve this?
So, you can do next:
in your Fragment class, you have recyclerview. Now, what you want to do is put the recyclerView.addOnScrollListener(new YourScrollListenerClass(context, toolbar, coordinatorLayout));
Coordinator layout is the one of the fragment, please bear that in mind.
Now, create a new class YourScrollListenerClass:
public class YourScrollListenerClass extends RecyclerView.OnScrollListener {
private Context mContext;
private Toolbar mToolbar;
private CoordinatorLayout mCoordinatorLayout;
private int mToolbarHeight;
private int mCoordinatorLayoutTopMargin;
public YourScrollListenerClass(Context context, #Nullable Toolbar toolbar, #Nullable final CoordinatorLayout mCoordinatorLayout) {
this.mContext = context;
mToolbar = toolbar;
this.mCoordinatorLayout = mCoordinatorLayout;
if (mToolbar != null && mCoordinatorLayout != null) {
mToolbar.post(new Runnable() {
#Override
public void run() {
mToolbarHeight = mToolbar.getHeight();
}
});
mCoordinatorLayout.post(new Runnable() {
#Override
public void run() {
mCoordinatorLayoutTopMargin = ((FrameLayout.LayoutParams) mCoordinatorLayout.getLayoutParams()).topMargin;
}
});
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (recyclerView != null) {
if (mToolbar != null) {
float offset = mToolbar.getTranslationY() - dy;
if (offset <= 0 && offset >= -(mToolbar.getHeight())) {
mToolbar.setTranslationY(mToolbar.getTranslationY() - dy);
FrameLayout.LayoutParams params1 = (FrameLayout.LayoutParams) mCoordinatorLayout.getLayoutParams();
params1.setMargins(0, params1.topMargin - dy, 0, 0);
mCoordinatorLayout.setLayoutParams(params1);
}
}
}
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (RecyclerView.SCROLL_STATE_IDLE == newState) {
if(mToolbar != null) {
if (Math.abs(mToolbar.getTranslationY()) <= mToolbar.getHeight() / 2) {
ObjectAnimator animator = ObjectAnimator.ofFloat(mToolbar, View.TRANSLATION_Y, mToolbar.getTranslationY(), 0);
animator.setDuration(300);
animator.start();
MarginAnimation animation = new MarginAnimation(mCoordinatorLayout, ((FrameLayout.LayoutParams) mCoordinatorLayout.getLayoutParams()).topMargin, mCoordinatorLayoutTopMargin);
mCoordinatorLayout.startAnimation(animation);
} else {
ObjectAnimator animator = ObjectAnimator.ofFloat(mToolbar, View.TRANSLATION_Y, mToolbar.getTranslationY(), -mToolbarHeight);
animator.setDuration(300);
animator.start();
MarginAnimation animation = new MarginAnimation(mCoordinatorLayout, ((FrameLayout.LayoutParams) mCoordinatorLayout.getLayoutParams()).topMargin, 0);
mCoordinatorLayout.startAnimation(animation);
}
}
}
}
}
And for the margin animation, create new Class
public class MarginAnimation extends Animation {
private View mView;
private float mToMargin;
private float mFromMargin;
private Context mContext;
public MarginAnimation(View v, float fromTop, float toTop) {
mFromMargin = fromTop;
mToMargin = toTop;
mView = v;
setDuration(300);
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float topMargin = (mToMargin - mFromMargin) * interpolatedTime + mFromMargin;
Log.d("TopMargin", String.valueOf(topMargin));
FrameLayout.LayoutParams p = (FrameLayout.LayoutParams) mView.getLayoutParams();
p.setMargins(0, (int) topMargin, 0, 0);
mView.setLayoutParams(p);
mView.requestLayout();
}
#Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
#Override
public boolean willChangeBounds() {
return true;
}
}
Hope this helps...
I have a layout with collapsing toolbar and a smooth transition of the avatar image along with title set via behavior. However, when the CircleImageView reaches the top, it suddenly gets overlapped by the toolbar. It seems like the toolbar is getting redrawn over CircleImageView (and with a shadow) when it gets fully collapsed.
Question is: how to make CircleImageView stay on top of the toolbar?
Gif with the bug at dropbox
Here is the xml code:
<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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:id="#+id/app_bar_layout"
>
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:id="#+id/collapsing_toolbar"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleTextAppearance="#style/ExpandedTitleText"
app:collapsedTitleTextAppearance="#style/CollapsedTitleText"
app:expandedTitleMarginStart="112dp"
app:expandedTitleMarginBottom="60dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_collapseMode="parallax"
android:paddingTop="?attr/actionBarSize"
android:paddingLeft="16dip"
android:paddingRight="16dip"
android:paddingBottom="16dip"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="group created by"
android:textColor="#color/text_secondary_white"
android:textSize="14sp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Admin name"
android:textColor="#color/text_secondary_white"
android:textSize="14sp"
android:id="#+id/admin"
/>
</LinearLayout>
</LinearLayout>
<android.support.v7.widget.Toolbar
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
app:theme="#style/ActionBar"
app:layout_collapseMode="pin"
android:id="#+id/toolbar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:id="#+id/recyclerView" />
<View
android:id="#+id/viewstub"
app:layout_anchor="#id/app_bar_layout"
app:layout_anchorGravity="bottom"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#android:color/black" />
<package.CustomView.CircleImageView
android:layout_width="80dip"
android:layout_height="80dip"
android:layout_marginLeft="16dip"
android:layout_marginTop="60dp"
tools:background="#color/color_accent"
android:id="#+id/get_avatar"
app:layout_behavior="package.AvatarImageBehavior" />
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/fab_margin"
app:layout_anchor="#id/app_bar_layout"
app:layout_anchorGravity="bottom|right|end"
app:backgroundTint="#color/color_accent"
app:borderWidth="0dp"
android:src="#drawable/ic_mode_edit_24dp"
android:id="#+id/fab" />
</android.support.design.widget.CoordinatorLayout>
AvatarImageBehavior.java - basically translates the CircleImageView to the toolbar. It depends on the stub view on the bottom of the appbar (not pretty, I know)
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 final Context mContext;
private float mAvatarMaxSize;
private float mFinalLeftAvatarPadding;
private float mStartPosition;
private int mStartXPosition;
private float mStartToolbarPosition;
public AvatarImageBehavior(Context context, AttributeSet attrs) {
mContext = context;
init();
mFinalLeftAvatarPadding = context.getResources().getDimension(
R.dimen.contact_space_left);
}
private void init() {
bindDimensions();
}
private void bindDimensions() {
mAvatarMaxSize = mContext.getResources().getDimension(R.dimen.contact_avatar);
}
private int mStartYPosition;
private int mFinalYPosition;
private int finalHeight;
private int mStartHeight;
private int mFinalXPosition;
#Override
public boolean layoutDependsOn(CoordinatorLayout parent, CircleImageView child, View dependency) {
return dependency.getId() == R.id.viewstub;
}
#Override
public boolean onDependentViewChanged(CoordinatorLayout parent, CircleImageView child, View dependency) {
maybeInitProperties(child, dependency);
float toolbarY = parent.findViewById(R.id.toolbar).getY();
// Log.w(TAG, "-----toolbar y: " + toolbarY);
int toolbarHeight = parent.findViewById(R.id.toolbar).getHeight();
// Log.w(TAG, "-----toolbar height: " + toolbarHeight);
// Log.w(TAG, "dependency.getY(): " + dependency.getY());
final int maxScrollDistance = (int)mStartToolbarPosition - toolbarHeight;
// Log.w(TAG, "maxScrollDistance: " + maxScrollDistance);
float expandedPercentageFactor = (dependency.getY()- toolbarHeight) / maxScrollDistance;
// Log.w(TAG, "expandedPercentageFactor: " + expandedPercentageFactor);
if(expandedPercentageFactor > 1f)expandedPercentageFactor = 1f;
float distanceYToSubtract = ((mStartYPosition - mFinalYPosition)
* (1f - expandedPercentageFactor));// + (child.getHeight()/2);
// Log.w(TAG, "distanceYToSubtract: " + distanceYToSubtract);
float distanceXToSubtract = ((mStartXPosition - mFinalXPosition)
* (1f - expandedPercentageFactor)) + (child.getWidth()/2);
// Log.w(TAG, "distanceXToSubtract: " + distanceXToSubtract);
float heightToSubtract = ((mStartHeight - finalHeight) * (1f - expandedPercentageFactor));
// Log.w(TAG, "heightToSubtract: " + heightToSubtract);
child.setY(mStartYPosition - distanceYToSubtract);
// Log.w(TAG, "child.setY: " + (mStartYPosition - distanceYToSubtract));
child.setX(mStartXPosition - distanceXToSubtract);
// Log.w(TAG, "child.setX: " + (mStartXPosition - distanceXToSubtract));
int proportionalAvatarSize = (int) (mAvatarMaxSize * (expandedPercentageFactor));
// Log.w(TAG, "proportionalAvatarSize: " + proportionalAvatarSize);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
lp.width = (int) (mStartHeight - heightToSubtract);
// Log.w(TAG, "lp.width: " + lp.width);
lp.height = (int) (mStartHeight - heightToSubtract);
// Log.w(TAG, "lp.height: " + lp.height);
child.setLayoutParams(lp);
// Log.w(TAG, "---------------------");
return true;
}
private void maybeInitProperties(CircleImageView child, View dependency) {
if (mStartYPosition == 0)
mStartYPosition = (int) child.getY();
// Log.w(TAG, "mStartYPosition: " + mStartYPosition);
if (mFinalYPosition == 0)
mFinalYPosition = mContext.getResources().getDimensionPixelOffset(R.dimen.contact_final_width);
// Log.w(TAG, "mFinalYPosition: " + mFinalYPosition);
if (mStartHeight == 0)
mStartHeight = child.getMeasuredHeight();
// Log.w(TAG, "mStartHeight: " + mStartHeight);
if (finalHeight == 0)
finalHeight = mContext.getResources().getDimensionPixelOffset(R.dimen.contact_final_width);
// Log.w(TAG, "finalHeight: " + finalHeight);
if (mStartXPosition == 0)
mStartXPosition = (int) (child.getX() + (child.getWidth() / 2));
// Log.w(TAG, "mStartXPosition: " + mStartXPosition);
if (mFinalXPosition == 0)
mFinalXPosition = mContext.getResources().getDimensionPixelOffset(R.dimen.abc_action_bar_content_inset_material) + (finalHeight*2);
// Log.w(TAG, "mFinalXPosition: " + mFinalXPosition);
if (mStartToolbarPosition == 0)
mStartToolbarPosition = dependency.getY();// 456
// Log.w(TAG, "mStartToolbarPosition: " + mStartToolbarPosition);
}
}
I wanna make footer buttons in android one way is to simply make buttons and align them to bottom but I want the footer like in Facebook android app whenever we drag screen down three buttons appears for status , photo , checkin.
How to do this ??
To get a list like the following image, create a layout.xml as follows after the sample image
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white" >
<RelativeLayout
android:id="#+id/headerLayout"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#drawable/header" >
<LinearLayout
android:id="#+id/BtnSlide"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_alignParentLeft="true"
android:background="#drawable/button_bg_drawable" >
<ImageView
android:id="#+id/imageView0"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_gravity="center_vertical|left"
android:background="#drawable/button_bg_drawable"
android:paddingBottom="10dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="10dp"
android:src="#drawable/back_btn_small" />
</LinearLayout>
<EditText
android:id="#+id/headerText"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:layout_toRightOf="#id/BtnSlide"
android:background="#android:drawable/editbox_background_normal"
android:editable="false"
android:textColor="#color/black"
android:textSize="18sp"
android:textStyle="normal" />
<AutoCompleteTextView
android:id="#+id/filterNewProject"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginRight="5dp"
android:layout_toRightOf="#id/BtnSlide"
android:background="#drawable/bg_input_blue"
android:completionThreshold="1"
android:hint="Search for a locality, developer or project"
android:textColor="#color/black"
android:textSize="14sp"
android:visibility="gone" />
<Button
android:id="#+id/clearAutoCompleteList"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:background="#drawable/custom_button_clear"
android:paddingLeft="20dp"
android:visibility="gone" />
<Button
android:id="#+id/searchButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:background="#drawable/seaerch_glass" />
<View
android:id="#+id/sep_header"
android:layout_width="fill_parent"
android:layout_height="2dp"
android:layout_below="#id/tabBar"
android:background="#d5d5d5"
android:visibility="visible" />
</RelativeLayout>
<include
android:id="#+id/footerLayout"
layout="#layout/post_requirement_footer"
android:visibility="gone" />
<ListView
android:id="#+id/projectsList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/footerLayout"
android:layout_below="#id/headerLayout"
android:divider="#color/white"
android:dividerHeight="1.5dp" >
</ListView>
<RelativeLayout
android:id="#+id/zeroResultsLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/footerLayout"
android:layout_below="#id/headerLayout"
android:visibility="gone" >
<ImageView
android:id="#+id/emptyIllustration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="#drawable/no_results_illustration" />
</RelativeLayout>
<com.housing.utils.QuickReturnRelativeLayoutFooter
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:background="#color/transparent" >
<RelativeLayout
android:id="#+id/bottomListViewContainer"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:background="#drawable/footer_bg" >
<ImageButton
android:id="#+id/filterButtonFooter"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="#drawable/button_bg_drawable"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:src="#drawable/filter_icon" />
<ImageButton
android:id="#+id/subscribeButtonFooter"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="#drawable/button_bg_drawable"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:src="#drawable/subscribe_iphone"
android:visibility="visible" />
<TextView
android:id="#+id/resultsText"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:ellipsize="end"
android:paddingTop="10dp"
android:scrollHorizontally="false"
android:singleLine="false"
android:text=""
android:textColor="#color/black"
android:textSize="15dp"
android:visibility="visible" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="#id/resultsText"
android:paddingRight="5dp"
android:paddingTop="15dp"
android:src="#drawable/filter_normal"
android:visibility="gone" />
</RelativeLayout>
</com.housing.utils.QuickReturnRelativeLayoutFooter>
</RelativeLayout>
Here is the Class com.housing.utils.QuickReturnRelativeLayoutFooter
PS : Replace com.housing.utils with your package name
package com.housing.utils;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.RelativeLayout;
public class QuickReturnRelativeLayoutFooter extends RelativeLayout implements
OnScrollListener {
private class ChildDescriptor {
public int index;
public int total;
public int drawable;
public ChildDescriptor(int index) {
this.index = index;
}
public int getApproximateScrollPosition() {
return index * total + (total - drawable);
}
}
public int MAX_HEIGHT_DP =60;
public int MIN_HEIGHT_DP = 0;
public static final int SCROLL_DIRECTION_INVALID = 0;
public static final int SCROLL_DIRECTION_UP = 1;
public static final int SCROLL_DIRECTION_DOWN = 2;
private int direction = SCROLL_DIRECTION_INVALID;
private ChildDescriptor lastchild;
private OnScrollListener onscrolllistener;
private int maxheight;
private int minheight;
public QuickReturnRelativeLayoutFooter(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
calculateMinMax();
}
public QuickReturnRelativeLayoutFooter(Context context, AttributeSet attrs) {
super(context, attrs);
calculateMinMax();
}
public QuickReturnRelativeLayoutFooter(Context context) {
super(context);
calculateMinMax();
}
private void calculateMinMax() {
DisplayMetrics metrics = getResources().getDisplayMetrics();
maxheight = (int) (metrics.density * (float) MAX_HEIGHT_DP);
minheight = (int) (metrics.density * (float) MIN_HEIGHT_DP);
}
private void adjustHeight(int howmuch, int max, int min) {
if ((howmuch < 0) && (direction != SCROLL_DIRECTION_UP)) {
direction = SCROLL_DIRECTION_UP;
return;
} else if ((howmuch > 20) && (direction != SCROLL_DIRECTION_DOWN)) {
direction = SCROLL_DIRECTION_DOWN;
return;
}
int current = getHeight();
current += howmuch;
if (current < min) {
current = min;
} else if (current > max) {
current = max;
}
RelativeLayout.LayoutParams f = (RelativeLayout.LayoutParams) getLayoutParams();
if (f.height != current) {
f.height = current;
setLayoutParams(f);
}
if (direction == SCROLL_DIRECTION_UP
&& Math.abs(f.topMargin) <= current) {
// if (f.topMargin != howmuch) {
//
// f.topMargin = howmuch + f.topMargin;
//
// if (f.topMargin > 0) {
// f.topMargin = -f.topMargin - 10;
// }
//
// }
// mBottomListViewContainer.setVisibility(View.GONE);
f.bottomMargin = -100;
setLayoutParams(f);
} else if (direction == SCROLL_DIRECTION_DOWN) {
if (f.bottomMargin != 0) {
f.bottomMargin = 0;
setLayoutParams(f);
}
}
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
ChildDescriptor currentchild = getFirstChildItemDescriptor(view,
firstVisibleItem);
try {
adjustHeight(lastchild.getApproximateScrollPosition()
- currentchild.getApproximateScrollPosition(), maxheight,
minheight);
lastchild = currentchild;
} catch (NullPointerException e) {
lastchild = currentchild;
} catch (Exception e) {
}
if (onscrolllistener != null) {
onscrolllistener.onScroll(view, firstVisibleItem, visibleItemCount,
totalItemCount);
}
}
private ChildDescriptor getFirstChildItemDescriptor(AbsListView view,
int index) {
ChildDescriptor h = new ChildDescriptor(index);
try {
Rect r = new Rect();
View child = view.getChildAt(0);
child.getDrawingRect(r);
h.total = r.height();
view.getChildVisibleRect(child, r, null);
h.drawable = r.height();
return h;
} catch (Exception e) {
}
return null;
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (onscrolllistener != null) {
onscrolllistener.onScrollStateChanged(view, scrollState);
}
}
public void attach(AbsListView view) {
view.setOnScrollListener(this);
}
public void setOnScrollListener(OnScrollListener l) {
onscrolllistener = l;
}
}
I Have made it as a widget and Now finally to add this to your List View use
frame = (QuickReturnRelativeLayoutFooter) newProjectsView
.findViewById(R.id.frame);
frame.attach(projectsList);
where projectList is your List View
example
ListView projectList =(ListView)findViewById(R.id.projectList);
and Voila Cheers Completed Smooth as Heaven .......