Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Menu item on bottom of CollapsingToolbarLayout when expanded

I've been searching for a while as shown on the following images but unfortunately I was not able to find anything similar

edit menu item is moving to bottom of CollapsingToolbarLayout when it is expanded

enter image description hereenter image description hereenter image description hereenter image description here

I tried a long combination of atributes for menu item but without success

This is my attempt

enter image description here

My screen 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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".ui.activities.AmbassadorActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/app_bar_height"
        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"
            app:toolbarId="@+id/toolbar">

            <ImageView
                android:id="@+id/photo"
                android:scaleType="centerCrop"
                android:transitionName="@string/ambassador_photo"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center"
                android:fitsSystemWindows="true"
                app:layout_collapseMode="parallax"
                android:contentDescription="@string/ambassador_photo" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:navigationIcon="@drawable/ic_arrow_back_white_24dp"
                app:popupTheme="@style/AppTheme.PopupOverlay" />

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_ambassador" />

</android.support.design.widget.CoordinatorLayout>

My menu xml

<menu 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"
    tools:context=".ui.activities.AmbassadorActivity">
    <item
        android:id="@+id/action_save"
        android:title="@string/save"
        android:icon="@drawable/ic_save_white_24dp"
        android:orderInCategory="300"
        app:showAsAction="always" />

    <item android:id="@+id/action_skills"
        android:title="@string/skills"
        app:showAsAction="ifRoom"
        android:orderInCategory="200"
        android:icon="@drawable/ic_local_activity_white_24dp"/>

    <item android:id="@+id/action_edit_name"
        android:title="@string/edit_name"
        app:showAsAction="ifRoom"
        android:orderInCategory="100"
        android:icon="@drawable/ic_edit_white_24dp"/>
</menu>

How to implement this menu item behavior like WhatsApp group?

Thanks for any suggestion!

like image 451
Abner Escócio Avatar asked Aug 14 '18 01:08

Abner Escócio


People also ask

What is collapsing toolbar?

CollapsingToolbarLayout is a wrapper for Toolbar which implements a collapsing app bar. It is designed to be used as a direct child of a AppBarLayout .

How do I stop my toolbar from collapsing?

The solution is simple, we just need to set the app:scrimAnimationDuration=”0" in our collapsing toolbar layout like the below code snippet. Now just run the code and see the results, you will see then there will be no fading animation anymore.


1 Answers

From the suggested project i will show you some modified approach to get your desired behaviour.

Also i added my project in github also Check Here

Demonstration

  1. Create top_view(which is visible in toolbar) & extended_view(which is visible in collapsing layout).
  2. Create custom class which is common to top_view & extended_view.
  3. Add Coordinatelayout behaviour to extended view.
  4. Update both views visibility,position & size based on AppBar onOffsetchangedListener.

Both TopView & ExtendedView should be same view which is stayed at top & extended in collapsing.

Here is the code

header_view.xml(Extended View)

<?xml version="1.0" encoding="utf-8"?>
<com.md.whatsappgroup_collapseview.HeaderView
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="wrap_content">

<TextView
    android:id="@+id/name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginEnd="@dimen/activity_horizontal_margin"
    android:layout_marginRight="@dimen/activity_horizontal_margin"
    android:layout_alignParentStart="true"
    android:layout_alignParentLeft="true"
    android:layout_toLeftOf="@+id/edit"
    android:layout_toStartOf="@id/edit"
    android:gravity="start|center_vertical"
    android:ellipsize="end"
    android:maxLines="1"
    android:textColor="@android:color/white"
    android:textSize="@dimen/header_view_start_text_size"
    android:textStyle="bold" />

<TextView
    android:id="@+id/description"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentStart="true"
    android:layout_alignParentLeft="true"
    android:layout_toLeftOf="@+id/edit"
    android:layout_toStartOf="@id/edit"
    android:singleLine="true"
    android:gravity="start"
    android:textColor="@android:color/white"
    android:layout_below="@+id/name"/>

<android.support.v7.widget.AppCompatImageButton
    android:id="@+id/edit"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"
    android:layout_centerVertical="true"
    android:background="@android:color/transparent"
    app:srcCompat="@drawable/ic_edit_white_24dp"
    />

</com.md.whatsappgroup_collapseview.HeaderView>

header_view_top.xml(Top View)

<?xml version="1.0" encoding="utf-8"?>
<com.md.whatsappgroup_collapseview.HeaderView
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="wrap_content">

<TextView
    android:id="@+id/name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginEnd="@dimen/activity_horizontal_margin"
    android:layout_marginRight="@dimen/activity_horizontal_margin"
    android:layout_alignParentStart="true"
    android:layout_alignParentLeft="true"
    android:layout_toLeftOf="@+id/edit"
    android:layout_toStartOf="@id/edit"
    android:gravity="start"
    android:ellipsize="end"
    android:maxLines="1"
    android:textColor="@android:color/white"
    android:textSize="@dimen/header_view_end_text_size"
    android:textStyle="bold" />

<TextView
    android:id="@+id/description"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentStart="true"
    android:layout_alignParentLeft="true"
    android:layout_toLeftOf="@+id/edit"
    android:layout_toStartOf="@id/edit"
    android:singleLine="true"
    android:gravity="start"
    android:textColor="@android:color/white"
    android:layout_below="@+id/name"/>

<android.support.v7.widget.AppCompatImageButton
    android:id="@+id/edit"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"
    android:layout_marginRight="8dp"
    android:layout_marginEnd="8dp"
    android:background="@android:color/transparent"
    app:srcCompat="@drawable/ic_edit_white_24dp"
    />

</com.md.whatsappgroup_collapseview.HeaderView>

activity_main.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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<android.support.design.widget.AppBarLayout
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/AppTheme.AppBarOverlay">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:fitsSystemWindows="true"
        app:scrimVisibleHeightTrigger="60dp"
        app:scrimAnimationDuration="300"
        app:statusBarScrim="@android:color/transparent"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

    <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:src="@drawable/photo"
        android:contentDescription="@string/thumbnail"
        app:layout_collapseMode="parallax" />

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@android:color/transparent"
        android:fitsSystemWindows="true"
        app:contentInsetStartWithNavigation="0dp"
        app:layout_collapseMode="pin"
        app:popupTheme="@style/AppTheme.PopupOverlay">

    <include
        android:id="@+id/toolbar_header_view"
        layout="@layout/header_view_top"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="gone" />

    </android.support.v7.widget.Toolbar>

    </android.support.design.widget.CollapsingToolbarLayout>

</android.support.design.widget.AppBarLayout>

<include
    android:id="@+id/float_header_view"
    layout="@layout/header_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_above="@+id/scrollView"
    app:layout_behavior="com.md.whatsappgroup_collapseview.HeaderBehaviour" />

<android.support.v4.widget.NestedScrollView
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

<include layout="@layout/content_main" />

</android.support.v4.widget.NestedScrollView>


</android.support.design.widget.CoordinatorLayout>

HeaderView.Java(Custom class)

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.RelativeLayout;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;

public class HeaderView extends RelativeLayout {

@BindView(R.id.name)
TextView tvName;

@BindView(R.id.description)
TextView tvDescription;

public HeaderView(Context context) {
    super(context);
}

public HeaderView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public HeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public HeaderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
}

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
    ButterKnife.bind(this);
}

public void bindTo(String name, String lastSeen) {
    this.tvName.setText(name);
    this.tvDescription.setText(lastSeen);
}

public void setTextSize(float size) {
    tvName.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
}

}

Header_behaviour.java

public class HeaderBehaviour extends CoordinatorLayout.Behavior<HeaderView> {

private Context mContext;

private int mStartMarginLeft;
private int mEndMarginLeft;
private int mMarginRight;
private int mStartMarginBottom;
private float mTitleStartSize;
private float mTitleEndSize;
private boolean isHide;

public HeaderBehaviour(Context context, AttributeSet attrs) {
    super(context, attrs);
    mContext = context;
}

public HeaderBehaviour(Context context, AttributeSet attrs, Context mContext) {
    super(context, attrs);
    this.mContext = mContext;
}

public static int getToolbarHeight(Context context) {
    int result = 0;
    TypedValue tv = new TypedValue();
    if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
        result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics());
    }
    return result;
}

@Override
public boolean layoutDependsOn(@NonNull CoordinatorLayout parent, @NonNull HeaderView child, @NonNull View dependency) {
    return dependency instanceof AppBarLayout;
}

@Override
public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, @NonNull HeaderView child, @NonNull View dependency) {
    shouldInitProperties();

    int maxScroll = ((AppBarLayout) dependency).getTotalScrollRange();
    float percentage = Math.abs(dependency.getY()) / (float) maxScroll;
    float childPosition = dependency.getHeight()
            + dependency.getY()
            - child.getHeight()
            - (getToolbarHeight(mContext) - child.getHeight()) * percentage / 2;

    childPosition = childPosition - mStartMarginBottom * (1f - percentage);

    CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
    if (Math.abs(dependency.getY()) >= maxScroll / 2) {
        float layoutPercentage = (Math.abs(dependency.getY()) - (maxScroll / 2)) / Math.abs(maxScroll / 2);
        lp.leftMargin = (int) (layoutPercentage * mEndMarginLeft) + mStartMarginLeft;
        lp.rightMargin = (int) (layoutPercentage * mEndMarginLeft) + mStartMarginLeft;
        child.setTextSize(getTranslationOffset(mTitleStartSize, mTitleEndSize, layoutPercentage));
    } else {
        lp.leftMargin = mStartMarginLeft;
        lp.rightMargin = mStartMarginLeft;
    }

    child.setLayoutParams(lp);
    child.setY(childPosition);

    if (isHide && percentage < 1) {
        child.setVisibility(View.VISIBLE);
        isHide = false;
    } else if (!isHide && percentage == 1) {
        child.setVisibility(View.GONE);
        isHide = true;
    }
    return true;
}

private float getTranslationOffset(float expandedOffset, float collapsedOffset, float ratio) {
    return expandedOffset + ratio * (collapsedOffset - expandedOffset);
}

private void shouldInitProperties() {
    if (mStartMarginLeft == 0) {
        mStartMarginLeft = mContext.getResources().getDimensionPixelOffset(R.dimen.header_view_start_margin_left);
    }

    if (mEndMarginLeft == 0) {
        mEndMarginLeft = mContext.getResources().getDimensionPixelOffset(R.dimen.header_view_end_margin_left);
    }

    if (mStartMarginBottom == 0) {
        mStartMarginBottom = mContext.getResources().getDimensionPixelOffset(R.dimen.header_view_start_margin_bottom);
    }

    if (mMarginRight == 0) {
        mMarginRight = mContext.getResources().getDimensionPixelOffset(R.dimen.header_view_end_margin_right);
    }

    if (mTitleStartSize == 0) {
        mTitleEndSize = mContext.getResources().getDimensionPixelSize(R.dimen.header_view_end_text_size);
    }

    if (mTitleStartSize == 0) {
        mTitleStartSize = mContext.getResources().getDimensionPixelSize(R.dimen.header_view_start_text_size);
    }
}


}

Mainactivity.java

public class MainActivity extends AppCompatActivity implements AppBarLayout.OnOffsetChangedListener{

@BindView(R.id.toolbar_header_view)
protected HeaderView toolbarHeaderView;

@BindView(R.id.float_header_view)
protected HeaderView floatHeaderView;

@BindView(R.id.appbar)
protected AppBarLayout appBarLayout;

@BindView(R.id.toolbar)
protected Toolbar toolbar;

@BindView(R.id.collapsing_toolbar)
protected CollapsingToolbarLayout collapsingToolbarLayout;

private boolean isHideToolbarView = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);

    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setDisplayShowTitleEnabled(false);

    initUi();

    /*Remove no need to change custom scrim colour */
    Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.photo);
    int color = getDominantColor(icon);
    collapsingToolbarLayout.setContentScrimColor(color);
    collapsingToolbarLayout.setStatusBarScrimColor(color);
    if (Build.VERSION.SDK_INT >= 21) {
        getWindow().setStatusBarColor(darker(color,0.8f));
    }
    /*Remove no need to change custom scrim colour*/


}

public static int darker (int color, float factor) {
    int a = Color.alpha( color );
    int r = Color.red( color );
    int g = Color.green( color );
    int b = Color.blue( color );

    return Color.argb( a,
            Math.max( (int)(r * factor), 0 ),
            Math.max( (int)(g * factor), 0 ),
            Math.max( (int)(b * factor), 0 ) );
}

public static int getDominantColor(Bitmap bitmap) {
    Bitmap newBitmap = Bitmap.createScaledBitmap(bitmap, 1, 1, true);
    final int color = newBitmap.getPixel(0, 0);
    newBitmap.recycle();
    return color;
}

private void initUi() {
    appBarLayout.addOnOffsetChangedListener(this);

    toolbarHeaderView.bindTo("Group Name", "Created by Developer");
    floatHeaderView.bindTo("Group Name", "Created by Developer");
}

@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {

    int maxScroll = appBarLayout.getTotalScrollRange();
    float percentage = (float) Math.abs(verticalOffset) / (float) maxScroll;

    if (percentage == 1f && isHideToolbarView) {
        toolbarHeaderView.setVisibility(View.VISIBLE);
        isHideToolbarView = !isHideToolbarView;

    } else if (percentage < 1f && !isHideToolbarView) {
        toolbarHeaderView.setVisibility(View.GONE);
        isHideToolbarView = !isHideToolbarView;
    }

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_person_add) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

}

OUTPUT

enter image description here

Hope this will help you.!

like image 115
Mohamed Mohaideen AH Avatar answered Sep 28 '22 04:09

Mohamed Mohaideen AH