前陣子,有個(gè)朋友讓我看手機(jī)淘寶app 我的淘寶,我的淘寶,那個(gè)可以滑動(dòng)用戶名。他們公司要用,他要做ios的可是我看到這個(gè)效果第一反應(yīng)是,這不就是,android5.0的一個(gè)控件嗎?沒錯(cuò)就是coordinatorlayout behavior 各種頭部動(dòng)畫,都可以他寫,關(guān)于,hehavior的帖子很多了。我就不在這里介紹了,大家可以隨意百度看解釋。
我們先看,最終效果圖。有圖有真相。

是不是,有點(diǎn)像,我必須說明,我是在源文件基礎(chǔ)上修改來的,這貼出來,原作者的git下載地址 :githup(雖然這個(gè)大牛也一定不會(huì)理我,但是做人要有道德)
其實(shí)如果你去他的githup看了。你就會(huì)發(fā)現(xiàn)我做的工作其實(shí)并不對(duì),沒事,真心不多,我就添加了一個(gè)toolbar,修來原有代碼不超過五行。是不是感覺有了互聯(lián)網(wǎng),我這種渣渣也能變成了。過程不重要,思路很重要。下來我們來看看具體我都修改了那些地方。
<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:ignore="RtlHardcoded">
<android.support.design.widget.AppBarLayout
android:id="@+id/main.appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/main.collapsing"
android:layout_width="match_parent"
android:layout_height="300dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<ImageView
android:id="@+id/main.imageview.placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/quila2"
android:tint="#11000000"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.9"
/>
//其實(shí)這個(gè)framelayout 已經(jīng)沒有什么用了。他的作用就是,一個(gè)高度展位,懶了一下,沒有調(diào)整。哈哈哈。
<FrameLayout
android:id="@+id/main.framelayout.title"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_gravity="bottom|center_horizontal"
android:background="@color/primary"
android:orientation="vertical"
android:visibility="invisible"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.3">
</FrameLayout>
//我添加的一個(gè)toolbar 其實(shí)就是再貼,修改了一下
<android.support.v7.widget.Toolbar
android:id="@+id/tools"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/cardview_light_background"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:layout_collapseMode="pin">
<LinearLayout
android:id="@+id/main.textview.title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/cardview_light_background"
android:gravity="center"
android:orientation="vertical">
//這里修改的是一個(gè)高度,就是這是這里,,,設(shè)置最終的高度,
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="@dimen/image_final_width"
android:layout_height="@dimen/image_final_width"
android:layout_gravity="center_horizontal"
android:src="@drawable/quila"
app:border_color="@android:color/holo_green_dark"
app:border_width="2dp"
/>
</LinearLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
app:behavior_overlapTop="30dp"
android:background="@color/cardview_light_background"
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:id="@+id/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>
//注意看,我隱藏掉了 toolbar,但是并沒有g(shù)one他,因?yàn)檫€是要讓他,占位置,讓我的小頭像跟隨
<android.support.v7.widget.Toolbar
android:id="@+id/main.toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/cardview_light_background"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:layout_anchor="@id/main.framelayout.title"
app:layout_collapseMode="pin"
android:visibility="invisible"
app:theme="@style/ThemeOverlay.AppCompat.Dark"
app:title="">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:gravity="center_vertical"
android:text="@string/quila_name2"
android:textColor="@android:color/white"
android:textSize="20sp" />
</LinearLayout>
</android.support.v7.widget.Toolbar>
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="@dimen/image_width"
android:layout_height="@dimen/image_width"
android:layout_gravity="center_horizontal"
android:src="@drawable/quila"
app:border_color="@android:color/holo_red_dark"
app:border_width="2dp"
app:finalHeight="@dimen/image_final_width"
app:finalYPosition="2dp"
app:layout_behavior="saulmm.myapplication.AvatarImageBehavior"
app:startHeight="2dp"
app:startToolbarPosition="2dp"
app:startXPosition="2dp" />
</android.support.design.widget.CoordinatorLayout>
其實(shí)就是一個(gè)道理,真亦假時(shí)假亦真,看到的不一定是真實(shí)的。都是虛幻,哈哈。也是之前看到,另一個(gè)大牛,寫爆炸android特效經(jīng)常用的,貫徹他的思路,我才能想到這個(gè)偷懶的方法。講講我的思路:
我們利用原有的toolbar作為,小頭像的移動(dòng)依靠,當(dāng)小頭像移動(dòng)到我們自己添加toolbar的位置的時(shí)候,將我們我們的toolbar顯示出來。
有人會(huì)提問,這尼瑪在逗我嗎?你這樣隱藏顯示的,有什么意義?
原因是這樣的:因?yàn)椴季值脑?。android5.0的toolbar 一定必須是頂層的吧。你的所有內(nèi)容都應(yīng)該是在他下面的吧。按照這個(gè)思路,我們就知道,其實(shí),為什么沒有隱藏小頭像的原因,那就是,我們把自己toolbar顯示出來就是,為了壓蓋這原有的小頭像。為了達(dá)到和淘寶的效果一樣,一瞬間掩藏。你會(huì)感覺,小頭像是流暢的跑到了toolbar上的其實(shí)不然,你松手就會(huì)被在AppBarLayout下的toolbar覆蓋掉。這就是為什么要要這個(gè)時(shí)候把原本準(zhǔn)備好的小頭像顯示出來的原因,如果我解釋的不太清楚,可以看看,我的圖片,我用綠色邊勾勒的是小頭像是我提前準(zhǔn)備好的那張頭像。
好了其實(shí)這些都不是我想說的重點(diǎn),重點(diǎn)是,大神寫的這個(gè)流暢的,Behavior
好了我需要在粘貼兩個(gè)重點(diǎn)的代碼。
private void maybeInitProperties(CircleImageView child, View dependency) {
if (mStartYPosition == 0)
mStartYPosition = (int) (dependency.getY());
if (mFinalYPosition == 0)
mFinalYPosition = (dependency.getHeight() /2);
if (mStartHeight == 0)
mStartHeight = child.getHeight();
if (mStartXPosition == 0)
mStartXPosition = (int) (child.getX() + (child.getWidth() / 2));
if (mFinalXPosition == 0)
mFinalXPosition = ((int) dependency.getWidth() / 2);
if (mStartToolbarPosition == 0)
mStartToolbarPosition = dependency.getY();
if (mChangeBehaviorPoint == 0) {
mChangeBehaviorPoint = (child.getHeight() - mCustomFinalHeight) / (2f * (mStartYPosition - mFinalYPosition));
}
}
看這個(gè)代碼的時(shí)候我準(zhǔn)備了一張圖片,雖然有點(diǎn)糙,但是湊合看吧

這就是大概一個(gè),邏輯圖片,說明了。大概要用的幾個(gè)屬性值是什么意思,這里最重點(diǎn)的是這句話
mChangeBehaviorPoint = (child.getHeight() - mCustomFinalHeight) / (2f * (mStartYPosition - mFinalYPosition));
一看就知道,他們要比例什么了,

簡(jiǎn)單解釋一下,一個(gè)兩個(gè)圓的差值 比矩形的差值還??2 這是要做什么,我看完整個(gè)代碼才懂,他是為了。一個(gè)位置上做縮放動(dòng)畫,讓縮放動(dòng)畫更加緊湊的一個(gè)過程,??2的意思其實(shí)就是增加除數(shù)值,讓這個(gè)動(dòng)畫相應(yīng)位置更加向上一點(diǎn)。必須說,我原本以為是一個(gè),數(shù)學(xué)表達(dá)式,結(jié)果好像不是的,是一個(gè)動(dòng)畫設(shè)計(jì)思路。
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, CircleImageView child, View dependency) {
maybeInitProperties(child, dependency);
final int maxScrollDistance = (int) (mStartToolbarPosition);
float expandedPercentageFactor = dependency.getY() / maxScrollDistance;
if (expandedPercentageFactor < mChangeBehaviorPoint) {
float heightFactor = (mChangeBehaviorPoint - expandedPercentageFactor) / mChangeBehaviorPoint;
float distanceXToSubtract = ((mStartXPosition - mFinalXPosition)
* heightFactor) + (child.getHeight()/2);
float distanceYToSubtract = ((mStartYPosition - mFinalYPosition)
* (1f - expandedPercentageFactor)) + (child.getHeight()/2);
child.setX(mStartXPosition - distanceXToSubtract);
child.setY(mStartYPosition - distanceYToSubtract);
float heightToSubtract = ((mStartHeight - mCustomFinalHeight) * heightFactor);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
lp.width = (int) (mStartHeight - heightToSubtract);
lp.height = (int) (mStartHeight - heightToSubtract);
child.setLayoutParams(lp);
} else {
float distanceYToSubtract = ((mStartYPosition - mFinalYPosition)
* (1f - expandedPercentageFactor)) + (mStartHeight/2);
child.setX(mStartXPosition - child.getWidth()/2);
child.setY(mStartYPosition - distanceYToSubtract);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
lp.width = (int) (mStartHeight);
lp.height = (int) (mStartHeight);
child.setLayoutParams(lp);
}
return true;
}
重點(diǎn)代碼
if (expandedPercentageFactor < mChangeBehaviorPoint)
一個(gè)if搞定了全世界,if后面的是小頭像縮放功能的已經(jīng)X、Y軸的移動(dòng)。else是處理,還原大小和位置移動(dòng)的僅僅是Y軸的。
就這樣,所有的工作都做完了。我不知道第一次的表達(dá),是不是夠清楚,其實(shí)源碼沒有修改什么,如果需要我可以,上傳,重點(diǎn)是,是原作者的思路。
我修改后的源碼
馬上準(zhǔn)備 ios的類似源碼分析,努力做到,ios和android一起跑著玩的節(jié)奏。希望能帶節(jié)奏。