CoordinatorLayout 子 View 之间的依赖管理机制 —— 有向无环图
写在前面这几天接触了 对于嵌套滑动 效果图这是一个模仿 源码https://github.com/fashare2015/DependencyBehavior 分析实现就不说了,只是定义一个
然后,用这个 建模 —— 有向无环图那 图的表示
public class CoordinatorLayout extends ViewGroup implements NestedScrollingParent {
private final List<View> mDependencySortedChildren = new ArrayList<>(); // 所有子节点
private final DirectedAcyclicGraph<View> mChildDag = new DirectedAcyclicGraph<>(); // 有向无环图,保存了边(依赖)的信息
}
建图
// 双重 for 循环,简单粗暴,
// 一个 O(N^2) 的算法,还能优化
private void prepareChildren(final boolean forceRefresh) {
...
// 枚举每个 child
for (int i = 0,count = getChildCount(); i < count; i++) {
final View view = getChildAt(i);
final LayoutParams lp = getResolvedLayoutParams(view);
mChildDag.addNode(view); // 在图中添加节点
// 枚举每个 otherChild
for (int j = 0; j < count; j++) {
if (j == i)
continue;
}
final View other = getChildAt(j);
final LayoutParams otherLp = getResolvedLayoutParams(other);
if (otherLp.dependsOn(this,other,view)) { // other dependsOn view
if (!mChildDag.contains(other))
mChildDag.addNode(other);
mChildDag.addEdge(view,other); // 添加边 view -> other
}
}
}
// getSortedList() 很关键,这里准备好 mDependencySortedChildren,
// 之后的 onMeasure(),onLayout() 都直接遍历它即可。
mDependencySortedChildren.addAll(mChildDag.getSortedList());
Collections.reverse(mDependencySortedChildren); // 之前建图建反了,这里拓扑序要反一下。
}
拓扑排序前面其实没细讲,为啥要有排序这一步?试想一下,如果不排序,直接
此时,再回过头看一下代码: // 之前的 mChildDag.getSortedList()
// 帮你实现了"拓扑排序"
final class DirectedAcyclicGraph<T> {
/** * Returns a topologically sorted list of the nodes in this graph. This uses the DFS algorithm * as described by Cormen et al. (2001). */
ArrayList<T> getSortedList() {
mSortResult.clear();
mSortTmpMarked.clear();
// Start a DFS from each node in the graph
// 深度优先搜索,求一个拓扑排序,具体不展开了
for (int i = 0,size = mGraph.size(); i < size; i++)
dfs(mGraph.keyAt(i),mSortResult,mSortTmpMarked);
return mSortResult;
}
}
之前的分析是基于 private void prepareChildren() {
... // 前面一样,添加节点到 mDependencySortedChildren
// 吐糟:为何不用快速排序
selectionSort(mDependencySortedChildren,mLayoutDependencyComparator); // 选择排序
}
// 重点看这个比较器,描述了两个节点之间的 "偏序关系",
// 也就是描述了 "谁该排在前面" 先 "onLayout()".
final Comparator<View> mLayoutDependencyComparator = new Comparator<View>() {
@Override
public int compare(View lhs,View rhs) {
if (lhs == rhs) {
return 0;
} else if (((LayoutParams) lhs.getLayoutParams()).dependsOn(
CoordinatorLayout.this,lhs,rhs)) { // r 为 dependency,得排在前面,需要交换一下
return 1;
} else if (((LayoutParams) rhs.getLayoutParams()).dependsOn(
CoordinatorLayout.this,rhs,lhs)) { // l 为 dependency,已经排在前面,不需要交换
return -1;
} else {
return 0;
}
}
};
总结以上便是 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |