前阵子,有个朋友让我看手机淘宝app 我的淘宝,我的淘宝,那个可以滑动用户名。他们公司要用,他要做ios的可是我看到这个效果第一反应是,这不就是,android5.0的一个控件吗?没错就是coordinatorlayout behavior 各种头部动画,都可以他写,关于,hehavior的帖子很多了。我就不在这里介绍了,大家可以随意百度看解释。
我们先看,最终效果图。有图有真相。
是不是,有点像,我必须说明,我是在源文件基础上修改来的,这贴出来,原作者的git下载地址 :githup(虽然这个大牛也一定不会理我,但是做人要有道德)
其实如果你去他的githup看了。你就会发现我做的工作其实并不对,没事,真心不多,我就添加了一个toolbar,修来原有代码不超过五行。是不是感觉有了互联网,我这种渣渣也能变成了。过程不重要,思路很重要。下来我们来看看具体我都修改了那些地方。
<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"
/>
//其实这个framelayout 已经没有什么用了。他的作用就是,一个高度展位,懒了一下,没有调整。哈哈哈。
<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>
//我添加的一个toolbar 其实就是再贴,修改了一下
<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">
//这里修改的是一个高度,就是这是这里,,,设置最终的高度,
<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,但是并没有gone他,因为还是要让他,占位置,让我的小头像跟随
<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>
其实就是一个道理,真亦假时假亦真,看到的不一定是真实的。都是虚幻,哈哈。也是之前看到,另一个大牛,写爆炸android特效经常用的,贯彻他的思路,我才能想到这个偷懒的方法。讲讲我的思路:
我们利用原有的toolbar作为,小头像的移动依靠,当小头像移动到我们自己添加toolbar的位置的时候,将我们我们的toolbar显示出来。
有人会提问,这尼玛在逗我吗?你这样隐藏显示的,有什么意义?
原因是这样的:因为布局的原因。android5.0的toolbar 一定必须是顶层的吧。你的所有内容都应该是在他下面的吧。按照这个思路,我们就知道,其实,为什么没有隐藏小头像的原因,那就是,我们把自己toolbar显示出来就是,为了压盖这原有的小头像。为了达到和淘宝的效果一样,一瞬间掩藏。你会感觉,小头像是流畅的跑到了toolbar上的其实不然,你松手就会被在AppBarLayout下的toolbar覆盖掉。这就是为什么要要这个时候把原本准备好的小头像显示出来的原因,如果我解释的不太清楚,可以看看,我的图片,我用绿色边勾勒的是小头像是我提前准备好的那张头像。
好了其实这些都不是我想说的重点,重点是,大神写的这个流畅的,Behavior
好了我需要在粘贴两个重点的代码。
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));
}
}
看这个代码的时候我准备了一张图片,虽然有点糙,但是凑合看吧
这就是大概一个,逻辑图片,说明了。大概要用的几个属性值是什么意思,这里最重点的是这句话
mChangeBehaviorPoint = (child.getHeight() - mCustomFinalHeight) / (2f * (mStartYPosition - mFinalYPosition));
一看就知道,他们要比例什么了,
简单解释一下,一个两个圆的差值 比矩形的差值还✖️2 这是要做什么,我看完整个代码才懂,他是为了。一个位置上做缩放动画,让缩放动画更加紧凑的一个过程,✖️2的意思其实就是增加除数值,让这个动画相应位置更加向上一点。必须说,我原本以为是一个,数学表达式,结果好像不是的,是一个动画设计思路。
@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;
}
重点代码
if (expandedPercentageFactor < mChangeBehaviorPoint)
一个if搞定了全世界,if后面的是小头像缩放功能的已经X、Y轴的移动。else是处理,还原大小和位置移动的仅仅是Y轴的。
就这样,所有的工作都做完了。我不知道第一次的表达,是不是够清楚,其实源码没有修改什么,如果需要我可以,上传,重点是,是原作者的思路。
我修改后的源码
马上准备 ios的类似源码分析,努力做到,ios和android一起跑着玩的节奏。希望能带节奏。