Android開源:BehaviorDemo-Behavior 實現的漂亮的效果
Behavior 實現的漂亮的效果
效果來源
原圖
我的實現
c.gif
一些細節沒有實現 ,見諒,錄制的gif效果也不太好 :-(
實現
依賴關系
Tab 監聽 onNestedPreScroll 來進行滑動, Toolbar 依賴 FytContent ,其余的依賴 Tab
變化
-
Tab 的移動是手指滑動距離的 1/2 ,會根據停下來的位置判斷是應該回到原位置還是下一個狀態并進行移動
-
VP 跟隨 Tab , HeaderScrollingViewBehavior 什么的請看建議,移動則沒什么難度
-
BGContent 跟隨 Tab ,根據 Tab 運動的比例,縮放,移動,修改 里面 View 的 Alpha
-
BG 跟隨 Tab ,首先向下移動到 BGContent 的高度的 1/2的地方
-
Editor 跟隨 Tab ,首先移動到 BGContent 下面加上預留的 Padding ,隨著比例移動并設置alpha
-
Icon 跟隨 Tab ,根據 Tab 運動的比例進行移動和調整大小
-
Name 同上
-
Socre 同上,沒有縮放
- ToolBarIcon 跟隨 BGContent ,根據 BGContent 移動的比例修改圖標的 Alpha
部分代碼
//TabBehavior
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
mUp = dy > 0;
if(isChildRequestScroll(child.getTranslationY())){//如果list需要滑動這邊就不動
consumed[1]=0;
return;
}
consumed[1]=dy;//全部消耗
int distance = -dy / 2;//降低移動的速度
if (child.getTranslationY() + distance < -mMaxDistance) {
distance = -mMaxDistance;
} else if (child.getTranslationY() + distance > 0) {
distance = 0;
} else {
distance = (int) (child.getTranslationY() + distance);
}
child.setTranslationY(distance);
}
/**
- Child是否需要滑動
*/
private boolean isChildRequestScroll(float translationY) {
return (translationY == -mMaxDistance &&//在頂部
mViewPager.getAdapter() != null && //有適配器
mViewPager.getAdapter().getCount() > 0 &&//有item
mViewPager.getAdapter() instanceof IsChildRequestScrollListener && //實現了
((IsChildRequestScrollListener) mViewPager.getAdapter()).requestScroll(mUp)//需要滑動
);
}
//設置 listener 檢測是否需要展開
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
mControlChange=true;
if(mViewPager.getAdapter() != null && //有適配器
mViewPager.getAdapter().getCount() > 0 &&//有item
mViewPager.getAdapter() instanceof SupportNeedExpendListener&&
((SupportNeedExpendListener) mViewPager.getAdapter()).getNeedExpendListener()==null){
((SupportNeedExpendListener) mViewPager.getAdapter()).setNeedExpendListener(this);
}
return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
}
/**
list fling到頭的時候 展開
*/
@Override
public void needExpand() {
if(!mControlChange){
mValueAnimator.setDuration(500);
mValueAnimator.removeAllUpdateListeners();
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mTab.setTranslationY((animation.getAnimatedFraction()-1)*mMaxDistance);
}
});
mValueAnimator.start();
}
}
/**
- 開啟硬件離屏緩存,放入不服導致緩存失效的 view
效果都還好
*/
if(mHardwareViews.size()==0){
mHardwareViews.add(parent.findViewById(R.id.txt_name));
mHardwareViews.add(parent.findViewById(R.id.img_icon));
mHardwareViews.add(parent.findViewById(R.id.lyt_score));
mHardwareViews.add(parent.findViewById(R.id.tab_layout));
mHardwareViews.add(parent.findViewById(R.id.bg));
mHardwareViews.add(parent.findViewById(R.id.lyt_editor));
mHardwareViews.add(parent.findViewById(R.id.lyt_statistics));
//開啟硬件離屏緩存
mValueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
for(View v:mHardwareViews){
v.setLayerType(View.LAYER_TYPE_NONE,null);
}
}
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
for(View v:mHardwareViews){
v.setLayerType(View.LAYER_TYPE_HARDWARE,null);
}
}
});
}</code></pre>
代碼是蠻簡單的 ,直接看項目即可,就那幾行代碼, 又加了點功能 耦合度變高了的感覺歡迎 Star,提 issue 還有PR
TODO
- 在向上fling的過程中,向下滑,會出現錯亂的情況 :-(