??AppBarLayout
有一個(gè)非常惡心的設(shè)計(jì)斯够,就是將自身的Fling完全內(nèi)部消化,從而導(dǎo)致了RecyclerView
之類的控件不能Fling。本文打算采用自定義Behavior
的方法來(lái)解決該問(wèn)題,應(yīng)該是如今網(wǎng)上最簡(jiǎn)單的方法腰根。
??我在思考自己的解決方法之前,在網(wǎng)上簡(jiǎn)單的搜索一番前人的答案拓型,發(fā)現(xiàn)已知的答案都非常的麻煩额嘿,好多的方法都是將AppBarLayout
相關(guān)代碼拷貝出來(lái),然后簡(jiǎn)單修改劣挫,工作量非常的大和復(fù)雜册养。本文將介紹作者本人思考出來(lái)的一種方法,本文的好處就是:你只定義兩個(gè)Behavior
就能實(shí)現(xiàn)压固。
1. 問(wèn)題的原因
??在解決的問(wèn)題球拦,我們先來(lái)看一下這個(gè)問(wèn)題產(chǎn)生的原因,問(wèn)題的原因在HeaderBehavior
里面有一段代碼:
case MotionEvent.ACTION_UP:
if (mVelocityTracker != null) {
mVelocityTracker.addMovement(ev);
mVelocityTracker.computeCurrentVelocity(1, 0.01f);
mVelocityTracker.computeCurrentVelocity(1000);
float yvel = mVelocityTracker.getYVelocity(mActivePointerId);
fling(parent, child, -getScrollRangeForDragFling(child), 0, yvel);
}
??fling的范圍是[ -getScrollRangeForDragFling(child), 0]
,這就導(dǎo)致了AppBarLayout
Fling到頂部就立即停止,原因的就是這樣坎炼,非常的簡(jiǎn)單愧膀。
2. 解決問(wèn)題
??我們要想解決這個(gè)問(wèn)題,就要從根本入手点弯。既然Fling不能傳遞出去導(dǎo)致的這個(gè)問(wèn)題扇调,我們就將它傳遞出去矿咕,如何傳遞出去呢抢肛?本文采用嵌套滑動(dòng)方式傳遞。
(1).自定義AppBarLayout的Behavior
??AppBarLayout
的Behavior
關(guān)鍵在于怎么將Fling傳遞出去碳柱,我們來(lái)看看捡絮,主要分為三步:
- 將
HeaderBehavior
中,將onTouchEvent
方法及其相關(guān)方法代碼拷貝出來(lái)- 在
AppBarLayout
Fling時(shí)莲镣,調(diào)用我們自己的fling方法(這里雖說(shuō)是自己的fing方法福稳,其實(shí)就是將原來(lái)的fling方法代碼拷貝出來(lái))。- 改寫
FlingRunnable
瑞侮,使Fling事件能順利傳遞出去的圆。
??在這其中,我們需要注意一點(diǎn):
- 調(diào)用fling方法進(jìn)行fling時(shí)半火,
minOffset
傳為Integer.MIN_VALUE
越妈,這樣這個(gè)Fling事件就可以肆意妄為了,不用局限于某一個(gè)范圍钮糖。
@Override
public boolean onTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
// ······
case MotionEvent.ACTION_UP:
if (velocityTracker != null) {
velocityTracker.addMovement(ev);
velocityTracker.computeCurrentVelocity(1000);
float yvel = velocityTracker.getYVelocity(activePointerId);
flingV2(parent, child, Integer.MIN_VALUE, 0, yvel);
}
// ······
}
??如上的代碼就是我們改寫了的部分梅掠,其中flingV2
方法就是我們自定義的fling方法,代碼與原來(lái)的fling
方法一模一樣店归。
??接下來(lái)改寫FlingRunnable
類阎抒,我們來(lái)看看:
private class FlingRunnable implements Runnable {
private final CoordinatorLayout parent;
private final AppBarLayout layout;
FlingRunnable(CoordinatorLayout parent, AppBarLayout layout) {
this.parent = parent;
this.layout = layout;
}
@Override
public void run() {
if (layout != null && scroller != null) {
if (scroller.computeScrollOffset()) {
scroll();
} else {
onFlingFinished(parent, layout);
}
}
}
private void scroll() {
// 如果AppBarLayout滑到閾值,此時(shí)需要將fling事件傳遞下去
if (scroller.getCurrY() <= -getScrollRangeForDragFling(layout) && scroller.getStartX() > scroller.getFinalY()) {
setHeaderTopBottomOffset(parent, layout, -getScrollRangeForDragFling(layout));
if (layout.startNestedScroll(View.SCROLL_AXIS_VERTICAL)) {
layout.dispatchNestedFling(scroller.getCurrVelocity(), scroller.getCurrVelocity(), false);
}
scroller.forceFinished(true);
} else { // 如果AppBarLayout還沒(méi)有滑到閾值消痛,就讓開心的滑動(dòng)且叁。
setHeaderTopBottomOffset(parent, layout, scroller.getCurrY());
}
ViewCompat.postOnAnimation(layout, this);
}
}
??AppBarLayout
自定義Behavior
流程到此結(jié)束了,接下來(lái)我們看一下RecyclerView
的Behavior
秩伞。
(2). 自定義RecyclerView的Behavior
??代碼如下:
public class FlingScrollingViewBehavior extends AppBarLayout.ScrollingViewBehavior {
public FlingScrollingViewBehavior() {
}
public FlingScrollingViewBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
return true;
}
@Override
public boolean onNestedFling(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, float velocityX, float velocityY, boolean consumed) {
if (child != target) {
((RecyclerView) (child)).fling((int) velocityX, (int) velocityY);
}
return true;
}
}
??然后我們?cè)趚ml中將Behavior
進(jìn)行綁定谴古,你就發(fā)現(xiàn),AppBarLayout
可以Fling了,效果如下:
3. 總結(jié)
?? 本方法非常的簡(jiǎn)單稠歉,到此就結(jié)束了掰担,不像網(wǎng)上其他方法那樣長(zhǎng)篇大論。在這里怒炸,我對(duì)本文做一個(gè)簡(jiǎn)單的總結(jié)带饱。
- 自定義AppBarLayout的Behavior,這其中一定保證把Fling事件傳遞出去。
- 自定義RecyclerView的Behavior中勺疼,可以通過(guò)
RecyclerView
的fling方法進(jìn)行fling教寂。