利用 CollapsingToolbarLayout 完成聯動的動畫效果
阿新 • • 發佈:2019-02-13
最近專案中需要實現個動畫效果,研究了下這裡做下簡單的分享.
效果圖如下:
最初的想法是自己去利用 Android 的巢狀滾動機制,去實現上面的巢狀滾動效果.但最後為了開發效率直接利用了 CollapsingToolbarLayout 和 CoordinatorLayout 的效果.
實現效果的原理十分簡單,監聽 CollapsingToolbarLayout 收縮和擴充套件的距離,換算成你想要的一個範圍比如移動的距離,縮放的比例.
部分原始碼:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android ="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.xf.mylab.activity.CollapsingToolbarLayoutTestActivity">
<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="com.wswy.chechengwang.view.activity.SubscriptionDetailActivity" >
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/subscription_head">
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height"
app:layout_collapseMode="pin">
<ImageView
android:id="@+id/back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_white_left_arrow" />
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/subscription_show"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="夏洛克的貓"
android:textSize="30sp" />
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/subscription_head"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_head"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_default_subscription" />
<TextView
android:id="@+id/subscription_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="夏洛克的貓"
android:textColor="@color/white"
android:textSize="16sp" />
<TextView
android:id="@+id/subscribe"
android:layout_width="75dp"
android:layout_height="24dp"
android:layout_marginTop="8dp"
android:button="@null"
android:checked="false"
android:gravity="center"
android:text="訂閱"
android:textColor="@color/white" />
</LinearLayout>
</FrameLayout>
public class CollapsingToolbarLayoutTestActivity extends AppCompatActivity {
private float mSelfHeight = 0;//用以判斷是否得到正確的寬高值
private float mTitleScale;
private float mSubScribeScale;
private float mSubScribeScaleX;
private float mHeadImgScale;
@Bind(R.id.iv_head)
ImageView mHeadImage;
@Bind(R.id.subscription_title)
TextView mSubscriptionTitle;
@Bind(R.id.subscribe)
TextView mSubscribe;
@Bind(R.id.app_bar)
AppBarLayout mAppBar;
@Bind(R.id.toolbar)
Toolbar mToolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collapsing_toolbar_layout_test);
ButterKnife.bind(this);
final float screenW = getResources().getDisplayMetrics().widthPixels;
final float toolbarHeight = getResources().getDimension(R.dimen.toolbar_height);
final float initHeight = getResources().getDimension(R.dimen.subscription_head);
mAppBar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (mSelfHeight == 0) {
mSelfHeight = mSubscriptionTitle.getHeight();
float distanceTitle = mSubscriptionTitle.getTop() + (mSelfHeight - toolbarHeight) / 2.0f;
float distanceSubscribe = mSubscribe.getY() + (mSubscribe.getHeight() - toolbarHeight) / 2.0f;
float distanceHeadImg = mHeadImage.getY() + (mHeadImage.getHeight() - toolbarHeight) / 2.0f;
float distanceSubscribeX = screenW / 2.0f - (mSubscribe.getWidth() / 2.0f + getResources().getDimension(R.dimen.normal_space));
mTitleScale = distanceTitle / (initHeight - toolbarHeight);
mSubScribeScale = distanceSubscribe / (initHeight - toolbarHeight);
mHeadImgScale = distanceHeadImg / (initHeight - toolbarHeight);
mSubScribeScaleX = distanceSubscribeX / (initHeight - toolbarHeight);
}
float scale = 1.0f - (-verticalOffset) / (initHeight - toolbarHeight);
mHeadImage.setScaleX(scale);
mHeadImage.setScaleY(scale);
mHeadImage.setTranslationY(mHeadImgScale * verticalOffset);
mSubscriptionTitle.setTranslationY(mTitleScale * verticalOffset);
mSubscribe.setTranslationY(mSubScribeScale * verticalOffset);
mSubscribe.setTranslationX(-mSubScribeScaleX * verticalOffset);
}
});
}
}
程式碼其實沒啥可說的,主要是一些距離的計算,主要就是頂在最上方時,文字都到了居中的位置.大家在圖中畫出開始和結束的位置,都能計算出來.
有一點提一下,最初我是把佈局嵌入到 CollapsingToolbarLayout 中去的,但是由於 CollapsingToolbarLayout 自身的收縮和擴充套件改變了自身高度,會影響裡面的 View 的位置,如果按照靜態的起始和結束位置計算,加上自身高度對 View 佈局的影響,這就複雜了,我沒有細研究.採用了一個笨拙的方式,用 FrameLayout 把佈局給抽取到頂部,不讓他們受到 CollapsingToolbarLayout 的影響.