CoordinatorLayout 是 support:design 提供的一個重要布局,雖然由于產品設計的原因,我在正式項目中還沒有機會使用到, 不過它提供了一些非常不錯的效果,值得記錄一下.
Android中處理事件分發還是挺麻煩的,需要從頂層開始,層層分發,攔截,響應.特別是涉及到多層嵌套的時候,需要判斷什么時候攔截,攔截后怎么處理;什么時候放行...
CoordinatorLayout 可以用于調度協調子布局,實現聯動效果.使用它,可以簡化事件的處理.下面是 CoordinatorLayout 的一些常用方式.
CoordinatorLayout 和 FloatingActionButton
FloatingActionButton就是一個按鈕,不過可以設置一些5毛特效.
<!--
app:backgroundTint 默認填充色
app:rippleColor 點擊時填充色
app:elevation 默認高度(高度越高,陰影越大)
app:pressedTranslationZ 點擊時高度
app:layout_anchor 依賴目標
app:layout_anchorGravity 相對依賴目標的位置
-->
Snackbar是從底部彈出的,當它顯示的時候,如果遮住了按鈕,體驗就不太好,CoordinatorLayout 就可以解決這個問題,當使用 CoordinatorLayout 作為容器時,如果顯示Snackbar,FloatingActionButton會有一個向上移動的效果
<?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">
<android.support.v4.widget.NestedScrollView
android:id="@+id/scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:text="@string/large_text" />
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_behavior="com.heihei.hehe.coordinatorlayout.behavior.FloatButtonBehavior"
app:layout_anchor="@id/scroll"
app:layout_anchorGravity="bottom|end"
app:backgroundTint="#fff000"
app:rippleColor="@color/colorAccent"
app:elevation="6dp"
app:pressedTranslationZ="12dp"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@android:drawable/ic_dialog_email" />
</android.support.design.widget.CoordinatorLayout>
關于FloatingActionButton,還可以實現一些更好的特效,不過需要涉及到 CoordinatorLayout 的原理,放在靠后一些的地方.
CoordinatorLayout 和 AppBarLayout
CoordinatorLayout 和 AppBarLayout一起使用,可以實現的效果有很多
Toolbar的快速返回
<?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">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
app:layout_scrollFlags="scroll|enterAlways"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:text="@string/large_text" />
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
內容上劃時,隱藏toolbar,下劃時,顯示toolbar,實現這個效果的關鍵在于
- 給滾動視圖添加屬性
// 只有添加了該屬性,才能讓CoordinatorLayout 響應子視圖的滾動事件
// 注: 滾動視圖必須要實現 NestedScrollingChild
app:layout_behavior="@string/appbar_scrolling_view_behavior" - toolbar放在 AppBarLayout 里面(暫時可以認為,只有AppBarLayout 里面的控件,才能響應滑動)
- 個toolbar添加屬性
app:layout_scrollFlags="scroll|..."
關于 app:layout_scrollFlags 還可以設置一些其它的值,實現的效果也有區別
scroll
這個值必須有,沒有這個值,控件會固定在屏幕上,不響應任何事件
snap
設置這個值后,toolbar不會停止在中間狀態,結束狀態要么完全顯示,要么完全隱藏
enterAlways
向上滾動,隱藏該控件;向下的滾動,顯示該控件
enterAlwaysCollapsed
向上滾動,隱藏該控件;
向下滑動:
a.沒有設置 minHeight,當滾動視圖到達頂部,再顯示該控件
b.設置 minHeight,先已最小高度出現,等滾動視圖到達頂部,再顯示該控件(同時需要設置 enterAlways 才生效)
exitUntilCollapsed
滾動視圖向上滾動時,該控件會折疊在頂部,這個在后面再具體說明
toolbar 搭配 tablayout 使用
<?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">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
app:layout_scrollFlags="scroll|enterAlways"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator"
app:popupTheme="@style/AppTheme.PopupOverlay" />
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable"
app:tabIndicatorHeight="3dp"
app:tabTextColor="@color/color_ffffff"
app:tabSelectedTextColor="@color/colorAccent"
app:tabIndicatorColor="@color/colorAccent"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:text="@string/large_text" />
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
順便解釋下TabLayout的一些屬性
app:tabMode 模式,有兩個值:scrollable(可滾動); fixed(固定的)
app:tabIndicatorHeight 指示滑塊的高度
app:tabTextColor 文字的顏色
app:tabSelectedTextColor 文字選中狀態的顏色
app:tabIndicatorColor 指示滑塊的顏色
app:layout_scrollFlags="scroll|enterAlwaysCollapsed|enterAlways"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
exitUntilCollapsed一般結合CollapsingToolbarLayout使用
<?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">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="250dp"
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:minHeight="?attr/actionBarSize"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:statusBarScrim="?attr/colorAccent"
app:title="title"
app:collapsedTitleGravity="left"
app:expandedTitleGravity="center_horizontal|bottom"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:src="@mipmap/icon_bg_mine"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
app:layout_collapseMode="pin"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:text="@string/large_text" />
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
上面的例子中,CollapsingToolbarLayout在滾動視圖上滑時,會逐漸收縮折疊在屏幕上方(折疊高度受最小高度影響). 同時 CollapsingToolbarLayout 的子視圖可以設置折疊模式
// 折疊模式
app:layout_collapseMode
有兩個值:
parallax -> 視差模式,就是上面的圖片的變化效果
pin -> 固定模式,在折疊的時候最后固定在頂端
// 視差效果
app:layout_collapseParallaxMultiplier
范圍[0.0,1.0],值越大視差越大
CollapsingToolbarLayout 中使用到的幾個屬性也解釋一下:
//折疊后的背景色 -> setContentScrim(Drawable)
app:contentScrim="?attr/colorPrimary"
// 必須設置透明狀態欄才有效 -> setStatusBarScrim(Drawable)
app:statusBarScrim="?attr/colorAccent"
// 標題
app:title="title"
// 折疊后的標題位置
app:collapsedTitleGravity="left"
// 打開時的標題位置
app:expandedTitleGravity="center_horizontal|bottom"
PS: AppbarLayout 的展開和關閉是可以通過代碼控制的
appbarLayout.setExpanded(true,false);
CoordinatorLayout 和 BottomSheet
通過 CoordinatorLayout 也可以實現底部彈窗的效果,并且效果更好
<android.support.v4.widget.NestedScrollView
android:id="@+id/scroll" android:layout_width="match_parent"
android:layout_height="300dp"
app:behavior_peekHeight="0dp"
app:behavior_hideable="true"
app:layout_behavior="@string/bottom_sheet_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:text="@string/large_text" />
</android.support.v4.widget.NestedScrollView>
可以看到,在 CoordinatorLayout 中,只要給某個視圖指定屬性
app:layout_behavior="@string/bottom_sheet_behavior"
就可以將該視圖變為底部菜單的形式,同時可以通過其它幾個屬性改變菜單的規則
// 關閉時的高度
app:behavior_peekHeight="0dp"
// 是否可以完全隱藏,如果指定為 false,那么將最少已上面的高度顯示
app:behavior_hideable="true"
代碼中控制
// 初始化
sheetBehavior = BottomSheetBehavior.from(findViewById(R.id.scroll));
// 打開
sheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
//關閉
sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
//隱藏
sheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
// 狀態監聽
sheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
// 狀態改變時回調
if(newState == BottomSheetBehavior.STATE_EXPANDED){
Toast.makeText(bottomSheet.getContext(),"打開了",Toast.LENGTH_SHORT).show();
}else if(newState == BottomSheetBehavior.STATE_COLLAPSED){
Toast.makeText(bottomSheet.getContext(),"關閉了",Toast.LENGTH_SHORT).show();
}else if(newState == BottomSheetBehavior.STATE_HIDDEN){
Toast.makeText(bottomSheet.getContext(),"隱藏了",Toast.LENGTH_SHORT).show();
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
// 拖動時回調
}
});
BottomSheetDialog
BottomSheetDialog 也是一種從底部彈起的對話框,使用起來和 CoordinatorLayout 沒什么關系,這里也一起介紹
// 直接通過構造方法初始化
BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(v.getContext());
//設置內容
bottomSheetDialog.setContentView(R.layout.content_scrolling);
//顯示
bottomSheetDialog.show();
常規的一些用法到這里差不多了. 那么為什么 CoordinatorLayout 可以實現這些效果? 因為在上面我們好像并沒有寫什么代碼,就是簡單的謝謝布局,設置一下屬性就可以了.
其實CoordinatorLayout自己并不控制View,所有的控制權都在Behavior. Behavior是 CoordinatorLayout 的內部內,是個抽象類. 它的子視圖通過實現Behavior,然后CoordinatorLayout就可以進行協同管理.
前面我們使用了AppBarLayout 和 FloatingActionButton ,可以去源碼里簡單的看一下
@CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
public class AppBarLayout extends LinearLayout {
...
@CoordinatorLayout.DefaultBehavior(FloatingActionButton.Behavior.class)
public class FloatingActionButton extends VisibilityAwareImageButton {
...
可以看到,這兩個控件都使用了Behavior,使用 Behavior的方式也有多種:
- 注解綁定Behavior,當我們使用自定義控件的時候,就可以像上面一樣,直接通過注解指定 Behavior.
- 在XML中綁定Behavior
app:layout_behavior="Behavior的包名" - 代碼綁定Behavior
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) view.getLayoutParams();
params.setBehavior(behavior);
同時,也可以通過自定義Behavior實現一些特殊的效果
// 如果該Behavior只想給某種控件使用,可以通過泛型控制, 當然也可以不指定,那么任何控件都可以使用
public class MyBehavior<T> extends CoordinatorLayout.Behavior {
// 構造方法必須要寫,因為Behavior最終都是通過反射此構造方法初始化
// 可以帶有自定義屬性
public MyBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
// 視圖依賴(想想觀察者模式),在這里可以指定具體的對象,也可以指定一個范圍
// 比如這里指定了,只觀察 AppBarLayout 的變化
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof AppBarLayout;
}
/**
* 依賴的對象發生了變化(觀察者 onNext...),可以在這里做出相應的處理,比如位置改變,大小變化等
* @param child 使用此 Behavior 的控件
* @param dependency 觀察的控件
*/
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
return true;
}
/**************************以下是滑動事件的相關方法(無需聲明依賴,不受依賴影響)*************************/
/**
* (嵌套)滾動事件開始前
* 通過返回值表示要不要響應本次滑動,只有這里返回true,后面的響應方法才會執行
* 比如這里,表示只響應垂直方向的滑動
* @param child 自己
* @param directTargetChild 發起滑動事件的控件
* @param target
*/
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
/**
* (嵌套)滾動事件開始后,滾動視圖獲得滾動事件前
* @param dy 垂直方向滑動增量
* @param consumed 長度為二 , 水平和垂直方向消耗掉的滾動
*/
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
//dy大于0是向上滾動 小于0是向下滾動
}
/**
* 滾動視圖獲得(嵌套)滾動事件后
* @param dyConsumed 豎直方向上滑動被消耗了多少
* @param dyUnconsumed 未消耗的
*/
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
if (dyConsumed > 0 && dyUnconsumed == 0) {
// 上滑
}
if (dyConsumed == 0 && dyUnconsumed > 0) {
// 到邊了, 還在上滑
}
if (dyConsumed < 0 && dyUnconsumed == 0) {
// 下滑
}
if (dyConsumed == 0 && dyUnconsumed < 0) {
// 到邊了, 還在下滑
}
}
// (嵌套)滾動事件結束后
@Override
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {
}
// 快速滑動開始前
@Override
public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY) { return false;
}
// 快速滑動
@Override
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY, boolean consumed) { return false;
}
}
自定義Behavior的套路就在上面,注釋很詳細了,下面是幾個具體的例子
1.FloatingActionButton 在向上滾動是隱藏,向下滾動時出現
public class FloatButtonBehavior extends FloatingActionButton.Behavior {
// 構造方法必須有,使用的時候,會通過反射調用該構造方法實例化, 如果沒有,會保錯
public FloatButtonBehavior(Context context, AttributeSet attrs) {
super();
}
@Override
public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child, final View directTargetChild, final View target, final int nestedScrollAxes) {
// Ensure we react to vertical scrolling
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
}
//上滑隱藏,下滑顯示
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed,dyUnconsumed);
if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
child.hide();
} else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
child.show();
}
}
}
2.底部菜單的上滑隱藏
public class BottomNavigationBehavior extends CoordinatorLayout.Behavior<View> {
private ObjectAnimator outAnimator,inAnimator;
public BottomNavigationBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
// 垂直滑動
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
if(dy > 0){//上滑隱藏
if(outAnimator == null){
outAnimator = ObjectAnimator.ofFloat(child,"translationY",0,child.getHeight());
outAnimator.setDuration(200);
}
if(!outAnimator.isRunning() && child.getTranslationY() <= 0){
outAnimator.start();
}
}else if(dy < 0){//下滑顯示
if(inAnimator == null){
inAnimator = ObjectAnimator.ofFloat(child,"translationY",child.getHeight(),0);
inAnimator.setDuration(200);
}
if(!inAnimator.isRunning() && child.getTranslationY() >= child.getHeight()){
inAnimator.start();
}
}
}
}
上面的例子用到了 support:design:25.0.0 里的一個新控件 BottomNavigationView
使用方式如下:
<!--
app:itemBackground 按鈕背景
app:itemIconTint 圖標顏色
app:itemTextColor 文字顏色
app:menu 菜單
-->
<android.support.design.widget.BottomNavigationView
android:id="@+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:layout_behavior="com.heihei.hehe.coordinatorlayout.behavior.BottomNavigationBehavior"
app:itemBackground="@color/color_1ec859"
app:itemIconTint="@drawable/tab_text_color_selector"
app:itemTextColor="@drawable/tab_text_color_selector"
app:menu="@menu/menu_navigation"/>
menu:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/item1"
android:checked="true"
android:icon="@android:drawable/stat_notify_chat"
android:title="Message"/>
<item
android:id="@+id/item2"
android:icon="@android:drawable/stat_notify_error"
android:title="Call"/>
<item
android:id="@+id/item3"
android:icon="@android:drawable/stat_notify_more"
android:title="Contact"/>
<item
android:id="@+id/item4"
android:icon="@android:drawable/stat_notify_sync"
android:title="aaa"/>
</menu>
代碼中設置:
navigationView = (BottomNavigationView) findViewById(R.id.navigation);
navigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.item1:
navigationView.setItemBackgroundResource(R.color.color_1ec859);
break;
case R.id.item2:
navigationView.setItemBackgroundResource(R.color.color_3b93eb);
break;
case R.id.item3:
navigationView.setItemBackgroundResource(R.color.color_ffa973);
break;
case R.id.item4:
navigationView.setItemBackgroundResource(R.color.color_ffbc00);
break;
}
Toast.makeText(BottomNavigationActivity.this, item.getTitle(), Toast.LENGTH_SHORT).show();
return false;
}
});
3.頭像動畫
public class HeaderImageBehavior extends CoordinatorLayout.Behavior {
private float distanceY;
public HeaderImageBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HeadBehavior);
distanceY = a.getDimension(R.styleable.HeadBehavior_openHeight,dip2px(context,250))//750 -a.getDimension(R.styleable.HeadBehavior_closeHeight,dip2px(context,56));//168
a.recycle();
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof AppBarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
float p = Math.abs(dependency.getY())*1f/distanceY; child.setScaleX(1- p/2);
child.setScaleY(1- p/2);
child.setTranslationX(-child.getLeft()*p);
return true;
}
private int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
CoordinatorLayout 還可以實現更復雜的效果,能力有限,就整理到這里了