sidhu眼中的CoordinatorLayout.Behavior(二)
前言
在上一節sidhu眼中的CoordinatorLayout.Behavior(一)中,我們講解了如何以通過Behavior來重寫某個控件的觸摸事件
可是我們只講了如何將觸摸事件拋出來,那怎么對這些數據進行處理呢?這就是我們今天要講的內容了,Behavior的嵌套滑動機制
首先我們來理解一下什么是嵌套滑動,了解Android Design的大家想必已經非常熟悉這種交互了
在一個控件滑動的同時,動態調整自身或其他控件的寬高或位置來達到更好的交互。
其實說白了,這個就是NestedScrollingParent和NestedScrollingChild的實際運用(不清楚的同學可以看這篇文章,Android 嵌套滑動機制(NestedScrolling))。仔細思考發現,實現嵌套滑動的關鍵,其實就是將自身的滑動事件告訴其他控件。現在大家知道我寫第一篇文章的那個Behavior的用途了吧,哈哈、
那我們就開始講解今天的內容,同樣,在文章的開始,我們先提出幾個疑問:
A發出消息,E也發出消息,怎樣判斷哪個是我們想要處理的滑動事件?
A使B變化的同時,A能否也能一起變化?
A使B發生改變的同時,B是否能發出消息,使C根據自己變化?
A發出消息,E也發出消息,怎樣判斷哪個是我們想要處理的滑動事件?
我們再來看一下之前提過的Behavior的處理邏輯圖
當收到觸摸事件后,CoordinatorLayout通知了所有的Behavior,換句話講,就是Behavior會收到自己不需要處理的滑動事件。
我們來重寫一下Behavior的onStartNestedScroll方法,會發現里面有個叫做target的View參數傳進來,而這個target就是發出這個滑動事件的View。其對應的,就是當初寫NestedScrollingChildHelper時,傳入的那個View。而onStartNestedScroll方法是在target調用了startNestedScroll的時候才被調用的,也就是滑動事件發出的起始時間點,所以此時用這個taget來判斷是否是我們所關心的那個view發出的最適合不過了。至于是用id(getId)還是類型(instanceof)來判斷就看你自己喜歡了、、
在onStartNestedScroll這個方法里,return true則對后續的操作進行處理,return false則忽略掉,后續方法不會被調用。
A使B變化的同時,A能否也能一起變化?
這個答案當然也是肯定的啦,你連target對象都拿到了,還有什么不能做,哈哈、、
說的多不如實戰練一下。那我們接著昨天的寫,網上很多都是根據滑動位移移到對應距離的例子,那我們不妨寫一個其他的例子:根據手勢的上滑下滑來用動畫效果隱顯頭部。
大致效果是這樣的
藍色部分用的是我們上一篇文章寫的Behavior,而紅色部分則用我們今天寫的Behavior。
先看一下xml文件
<?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"android:layout_width="match_parent"android:layout_height="match_parent"><Viewandroid:id="@+id/rel_head"android:layout_width="match_parent"android:layout_height="200dp"android:background="@color/colorAccent"app:layout_behavior=".HideHeadBehavior" /><Viewandroid:id="@+id/rel_body"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginTop="200dp"android:background="@color/colorPrimaryDark"app:layout_behavior=".TouchBehavior" /></android.support.design.widget.CoordinatorLayout>布局很簡單,上面有個200dp高的紅色部分,紅色下面是藍色部分
Activity更簡單,因為它什么都不用做、、
public class TouchTestActivity extends AppCompatActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_touch_text);}}那重點是我們的Behavior了
package com.mintmedical.mybehaviordemo;import android.animation.ValueAnimator; import android.content.Context; import android.support.design.widget.CoordinatorLayout; import android.util.AttributeSet; import android.view.View;/*** Created by SidHu on 2016/8/17.*/ public class HideHeadBehavior extends CoordinatorLayout.Behavior {private boolean isHeadHide = false;private boolean isAnimating = false;private final int SCROOL_VALUE = 50;private int childHeight;private final int animationDuration = 500;public HideHeadBehavior(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {if (target.getId() == R.id.rel_body) {if (childHeight == 0) {childHeight = child.getHeight();}return true;} else {return false;}}@Overridepublic void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);if (isAnimating) {return;}if (dy > SCROOL_VALUE && !isHeadHide) {hide(child, target);} else if (dy < -SCROOL_VALUE && isHeadHide) {show(child, target);}}public void hide(final View child, final View target) {isHeadHide = true;ValueAnimator valueAnimator = new ValueAnimator();valueAnimator.setIntValues(0, childHeight);valueAnimator.setDuration(animationDuration);valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {if (child.getBottom() > 0) {int value = (int) animation.getAnimatedValue();isAnimating = value != childHeight;child.layout(child.getLeft(), -value, child.getRight(), -value + childHeight);target.layout(target.getLeft(), -value + childHeight, target.getRight(), target.getBottom());}}});valueAnimator.start();}public void show(final View child, final View target) {isHeadHide = false;ValueAnimator valueAnimator = new ValueAnimator();valueAnimator.setIntValues(0, childHeight);valueAnimator.setDuration(animationDuration);valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {if (child.getBottom() < childHeight) {int value = (int) animation.getAnimatedValue();isAnimating = value != childHeight;child.layout(child.getLeft(), value - childHeight, child.getRight(), value);target.layout(target.getLeft(), value, target.getRight(), target.getBottom());}}});valueAnimator.start();}}代碼簡直非~~非~非常簡單,對嘛,寫demo就是要簡單,有時候看別人寫的demo,無關業務一大堆,代碼老長,看了半天才找到那句對我有用的代碼。
這個類里,排除兩個值動畫,只有兩個方法
判斷是否為我們關心的target對象,是返回true,否返回false,順便獲取了下child(也就是紅色部分)的高度。
@Override public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);if (isAnimating) {return;}if (dy > SCROOL_VALUE && !isHeadHide) {hide(child, target);} else if (dy < -SCROOL_VALUE && isHeadHide) {show(child, target);} }接收到滑動數據后,假如動畫結束,對滑動的值進行一個閾值和方向的判斷,然后調用對應動畫。
而在值動畫里面,我們就僅僅不停改變Head和Body的Layout位置,實現動畫效果、
整個類就解釋完了!快去試試在手機上的運行效果吧、
A使B發生改變的同時,B是否能發出消息,使C根據自己變化?
就得嘛得!!!!
不是還有一個問題嘛、、、
這個問題的回答當然也是肯定的啦,其實聰明的你或許已經猜想到應該怎么實現了,沒錯,就是根據第一篇文章依葫蘆畫瓢嘛。哈哈,趕緊試一試吧、不過到時候我寫的會有點稍微不一樣,因為下一篇要講的是:Behavior的布局依賴、、
sidhu眼中的CoordinatorLayout.Behavior(三)
如果覺得這篇文章對你有幫助,點個贊鼓勵一下吧、、(●'?'●)
總結
以上是生活随笔為你收集整理的sidhu眼中的CoordinatorLayout.Behavior(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: node(ActiveMq)
- 下一篇: C++对象模型详解(上)