Skip to content

Instantly share code, notes, and snippets.

@Zoha131
Last active May 12, 2019 10:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Zoha131/3f961f537ea0dedf9fa409a601f3d484 to your computer and use it in GitHub Desktop.
Save Zoha131/3f961f537ea0dedf9fa409a601f3d484 to your computer and use it in GitHub Desktop.
Custom CoordinatorLayout Behavior
<!--suppress XmlUnusedNamespaceDeclaration -->
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:card_view="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:ignore="HardcodedText">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<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">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<ImageView
android:id="@+id/imageview_placeholder"
android:layout_width="match_parent"
android:layout_height="400dp"
android:contentDescription="@string/app_name"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:tint="#11000000"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.9" />
<FrameLayout
android:id="@+id/framelayout_title"
android:layout_width="match_parent"
android:layout_height="130dp"
android:layout_gravity="bottom|center_horizontal"
android:background="@color/colorPrimary"
android:fitsSystemWindows="true"
android:orientation="vertical"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.3">
<LinearLayout
android:id="@+id/linearlayout_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:paddingBottom="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="bottom|center"
android:text="Grumpy Cat"
android:textColor="@android:color/white"
android:textSize="30sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="4dp"
android:text="The famous meme"
android:textColor="@android:color/white" />
</LinearLayout>
</FrameLayout>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/nestedView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/activity_horizontal_margin"
android:scrollbars="none"
app:behavior_overlapTop="50dp"
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/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark"
app:layout_anchor="@id/framelayout_title">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<Space
android:layout_width="@dimen/image_small_width"
android:layout_height="@dimen/image_small_width" />
<TextView
android:id="@+id/textview_title"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:gravity="center_vertical"
android:text="Grumpy Cat information"
android:textColor="@android:color/white"
android:textSize="20sp" />
</LinearLayout>
</android.support.v7.widget.Toolbar>
<de.hdodenhof.circleimageview.CircleImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/avatar"
android:layout_width="@dimen/image_width"
android:layout_height="@dimen/image_width"
android:layout_gravity="center"
android:src="@drawable/avater"
app:civ_border_color="#FFff"
app:civ_border_width="2dp"
app:layout_behavior="io.github.zoha131.custombehavioronefinal.ImageBehavior" />
</android.support.design.widget.CoordinatorLayout>
</android.support.v4.widget.DrawerLayout>
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:design:27.1.0'
compile 'com.android.support:cardview-v7:27.1.0'
compile 'de.hdodenhof:circleimageview:2.2.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="image_width">110dp</dimen>
<dimen name="image_small_width">32dp</dimen>
</resources>
package io.github.zoha131.custombehavioronefinal;
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.support.v7.widget.Toolbar;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class ImageBehavior<T extends View> extends CoordinatorLayout.Behavior<T> {
private final static String TAG = "ImageBehavior";
private final Context mContext;
private int mStartXPosition;
private float mStartToolbarPosition;
private int mStartYPosition;
private int mFinalYPosition;
private int finalHeight;
private int mStartHeight;
private int mFinalXPosition;
private int maxScrollDistance;
public ImageBehavior(Context context, AttributeSet attrs) {
mContext = context;
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof Toolbar;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
maybeInitProperties(child, dependency);
float expandedPercentageFactor = dependency.getY() / maxScrollDistance;
float distanceYToSubtract = ((mStartYPosition - mFinalYPosition)
* (1f - expandedPercentageFactor)) + (child.getHeight()/2);
float distanceXToSubtract = ((mStartXPosition - mFinalXPosition)
* (1f - expandedPercentageFactor)) + (child.getWidth()/2);
float heightToSubtract = ((mStartHeight - finalHeight) * (1f - expandedPercentageFactor));
Log.d(TAG, "expandedPercentageFactor "+expandedPercentageFactor);
Log.d(TAG, "distanceYToSubtract "+distanceYToSubtract);
Log.d(TAG, "distanceXToSubtract "+distanceXToSubtract);
Log.d(TAG, "heightToSubtract "+heightToSubtract);
Log.d(TAG, " ");
Log.d(TAG, " ");
child.setY(mStartYPosition - distanceYToSubtract);
child.setX(mStartXPosition - distanceXToSubtract);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
lp.width = (int) (mStartHeight - heightToSubtract);
lp.height = (int) (mStartHeight - heightToSubtract);
child.setLayoutParams(lp);
return true;
}
@SuppressLint("PrivateResource")
private void maybeInitProperties(View child, View dependency) {
if (mStartYPosition == 0)
mStartYPosition = (int) (dependency.getY());
if (mFinalYPosition == 0)
mFinalYPosition = (dependency.getHeight() /2) + 8;
if (mStartHeight == 0)
mStartHeight = child.getHeight();
if (finalHeight == 0)
finalHeight = mContext.getResources().getDimensionPixelOffset(R.dimen.image_small_width);
if (mStartXPosition == 0)
mStartXPosition = (int) (child.getX() + (child.getWidth() / 2));
//TODO: edit mFinalXPosition to make room for Toggle Button of Navigation Drawer
//Just add or subtract constant to adjust the final x position
if (mFinalXPosition == 0)
mFinalXPosition = mContext.getResources().getDimensionPixelOffset(R.dimen.abc_action_bar_content_inset_material) + (finalHeight / 2) - 55;
if (mStartToolbarPosition == 0)
mStartToolbarPosition = dependency.getY() + (dependency.getHeight()/2);
if (maxScrollDistance == 0){
maxScrollDistance = (int) (mStartToolbarPosition - getStatusBarHeight());
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) dependency.getLayoutParams();
lp.setMargins(0,getStatusBarHeight(),0,0);
dependency.setLayoutParams(lp);
}
Log.d(TAG, "mStartYPosition "+mStartYPosition);
Log.d(TAG, "mFinalYPosition "+mFinalYPosition);
Log.d(TAG, "mStartHeight "+mStartHeight);
Log.d(TAG, "finalHeight "+finalHeight);
Log.d(TAG, "mStartXPosition "+mStartXPosition);
Log.d(TAG, "mFinalXPosition "+mFinalXPosition);
Log.d(TAG, "mStartToolbarPosition "+mStartToolbarPosition);
Log.d(TAG, "maxScrollDistance "+maxScrollDistance);
Log.d(TAG, " ");
}
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;
}
}
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/setting"
android:title="@string/app_name"
app:showAsAction="never"/>
<item android:id="@+id/menu_share"
android:icon="@drawable/like"
app:showAsAction="ifRoom"
android:title="@string/app_name" />
</menu>
package io.github.zoha131.custombehavioronefinal;
import android.os.Bundle;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import de.hdodenhof.circleimageview.CircleImageView;
public class MainActivity extends AppCompatActivity implements AppBarLayout.OnOffsetChangedListener {
private static final float PERCENTAGE_TO_SHOW_TITLE_AT_TOOLBAR = 0.9f;
private static final float PERCENTAGE_TO_HIDE_TITLE_DETAILS = 0.3f;
private static final int ALPHA_ANIMATIONS_DURATION = 200;
private boolean mIsTheTitleVisible = false;
private boolean mIsTheTitleContainerVisible = true;
private AppBarLayout appbar;
private CollapsingToolbarLayout collapsing;
private ImageView coverImage;
private FrameLayout framelayoutTitle;
private LinearLayout linearlayoutTitle;
private Toolbar toolbar;
private TextView textviewTitle;
private CircleImageView avatar;
/**
* Find the Views in the layout<br />
* <br />
* Auto-created on 2016-03-03 11:32:38 by Android Layout Finder
* (http://www.buzzingandroid.com/tools/android-layout-finder)
*/
private void findViews() {
appbar = (AppBarLayout)findViewById( R.id.appbar );
collapsing = (CollapsingToolbarLayout)findViewById( R.id.collapsing );
coverImage = (ImageView)findViewById( R.id.imageview_placeholder );
framelayoutTitle = (FrameLayout)findViewById( R.id.framelayout_title );
linearlayoutTitle = (LinearLayout)findViewById( R.id.linearlayout_title );
toolbar = (Toolbar)findViewById( R.id.toolbar );
textviewTitle = (TextView)findViewById( R.id.textview_title );
avatar = (CircleImageView)findViewById(R.id.avatar);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViews();
toolbar.setTitle("");
appbar.addOnOffsetChangedListener(this);
setSupportActionBar(toolbar);
startAlphaAnimation(textviewTitle, 0, View.INVISIBLE);
//set avatar and cover
coverImage.setImageResource(R.drawable.background);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int offset) {
int maxScroll = appBarLayout.getTotalScrollRange();
float percentage = (float) Math.abs(offset) / (float) maxScroll;
handleAlphaOnTitle(percentage);
handleToolbarTitleVisibility(percentage);
}
private void handleToolbarTitleVisibility(float percentage) {
if (percentage >= PERCENTAGE_TO_SHOW_TITLE_AT_TOOLBAR) {
if(!mIsTheTitleVisible) {
startAlphaAnimation(textviewTitle, ALPHA_ANIMATIONS_DURATION, View.VISIBLE);
mIsTheTitleVisible = true;
}
} else {
if (mIsTheTitleVisible) {
startAlphaAnimation(textviewTitle, ALPHA_ANIMATIONS_DURATION, View.INVISIBLE);
mIsTheTitleVisible = false;
}
}
}
private void handleAlphaOnTitle(float percentage) {
if (percentage >= PERCENTAGE_TO_HIDE_TITLE_DETAILS) {
if(mIsTheTitleContainerVisible) {
startAlphaAnimation(linearlayoutTitle, ALPHA_ANIMATIONS_DURATION, View.INVISIBLE);
mIsTheTitleContainerVisible = false;
}
} else {
if (!mIsTheTitleContainerVisible) {
startAlphaAnimation(linearlayoutTitle, ALPHA_ANIMATIONS_DURATION, View.VISIBLE);
mIsTheTitleContainerVisible = true;
}
}
}
public static void startAlphaAnimation (View v, long duration, int visibility) {
AlphaAnimation alphaAnimation = (visibility == View.VISIBLE)
? new AlphaAnimation(0f, 1f)
: new AlphaAnimation(1f, 0f);
alphaAnimation.setDuration(duration);
alphaAnimation.setFillAfter(true);
v.startAnimation(alphaAnimation);
}
}
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
</resources>
@Zoha131
Copy link
Author

Zoha131 commented Mar 1, 2018

custom_behavior

@Zoha131
Copy link
Author

Zoha131 commented Mar 1, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment