其实Behavior就是一个应用于View的观察者模式,一个View跟随者另一个View的变化而变化,或者说一个View监听另一个View。
在Behavior中,被观察View 也就是事件源被称为dependency,而观察View,则被称为child。
两个简单的控件进行一起滑动
ButtonFragment中:
1 | dependBtn.setOnTouchListener(new View.OnTouchListener() { |
buttonBehavior 中:
1 |
|
UC浏览器主页demo
主要是这4个重要的类
布局说明:
UCTitleView
UCTitleView如果要在content滑动结束刚刚全部出来
应该是:
float ratio = UCTitleView的滑动距离 / content的滑动距离
由于初始状态是从上面往下面走,所以是 负的
直接用 -1 * offset 控件会保持不动
所以:UCTitleView移动距离 = -(1 + ratio) * offset
1
2
3
4
5
6
7
8
9UCHeaderView headerView = (UCHeaderView) viewGroup;
int scrollRange = headerView.getScrollRange();
float ratio = getMeasuredHeight() / (float) scrollRange;
//负号是往下面移动
//如果直接是-offset,控件是原地不动的
//经过计算, 如果重上往下走 如果是控件全部出来这一种 移动一个控件的高度就好了
//即: -(1 + (控件高度/recyclerView滑动总距离)) * offset
//offset的max是 recyclerView滑动总距离
mATViewOffsetHelper.setTopAndBottomOffset((int) (-(ratio + 1) * offset));UCTabLayout
UCTabLayout如果要滑动刚刚和和UCTitleView全部划出来的地方
距离应该是: 滑动高度 = UCCenterView的高度 - content的滑动距离 - UCTitleView的高度
从而得出了倍率: float ratio = 滑动高度/content的滑动距离
所以:
UCTabLayout动态移动距离 = ratio * offset
1
2
3
4
5
6UCHeaderView headerView = (UCHeaderView) viewGroup;
int scrollRange = headerView.getScrollRange();
int height = headerView.getCenterViewHeight();
int currentScroll = height - scrollRange;
float ratio = (currentScroll - headerView.getTitleHeight()) / (float) scrollRange;
mATViewOffsetHelper.setTopAndBottomOffset((int) (ratio * offset));UCScrollingBehavior
UCScrollingBehavior主要用来放在 RecyclerView(也可以是其他实现了NestedScrollChild的接口View) 上面的一个behavior,用于把 UCHeaderView和RecyclerView摆放位置确定的类部分代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28/**
* 一开始确定
* UCHeaderView 和 recyclerView的摆放
*/
public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, @NonNull View child, @NonNull View dependency) {
UCHeaderView headerView = findFirstDependency(parent.getDependencies(child));
if (headerView != null) {
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) headerView.getLayoutParams();
CoordinatorLayout.Behavior behavior = layoutParams.getBehavior();
if (behavior instanceof UCHeaderView.Behavior) {
// UCHeaderView.Behavior headerBehavior = (UCHeaderView.Behavior) behavior;
ViewCompat.offsetTopAndBottom(child, dependency.getBottom() - child.getTop() - (headerView).getTitleHeight() - (headerView).getBarRange());
}
}
return super.onDependentViewChanged(parent, child, dependency);
}
/**
* 限制 content 滑动范围
*/
protected int getScrollRange(View v) {
if (v instanceof UCHeaderView) {
return ((UCHeaderView) v).getScrollRange() + ((UCHeaderView) v).getTitleHeight() + ((UCHeaderView) v).getBarRange();
}
return super.getScrollRange(v);
}UCHeaderView
UCHeaderView决定头部里面所有控件的摆放和移动, 通过里面的behavior进行确定偏移(offset)
UCTitleView 摆放在手机屏幕上面的外面,UCTitleView的bottom在上面屏幕的边界上
UCCenterView 正常的摆放以自己的高度的高度进行了摆放
UCTabLayout 摆在了UCCenterView后面,只不过UCTabLayout会在摆放的RecyclerView的下面,所以在UCScrollingBehavior中onDependentViewChanged和getScrollRange方法进行了体现.
1 | /** |