Last active
May 12, 2019 10:51
-
-
Save Zoha131/3f961f537ea0dedf9fa409a601f3d484 to your computer and use it in GitHub Desktop.
Custom CoordinatorLayout Behavior
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
Author
Zoha131
commented
Mar 1, 2018
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment