前语
使用RecyclerView和ScrollView等体系供给的滑动控件,需求边际淡化,只需求装备requiresFadingEdge和fadingEdgeLength,指定淡化的方向和长度即可,很遗憾CoordinatorLayout并不支撑这些特点。
requiresFadingEdge特点用于在视图的边际添加淡出作用,当内容超出边界时,能够通过滚动视图来显现淡出作用。但是,CoordinatorLayout是一个布局容器,它的主要功能是协调子视图之间的交互和动作,并管理它们的方位和行为。它并不直接处理滚动,而是将滚动事情传递给子视图处理。
CoordinatorLayout的规划意图是协调子视图之间的交互和动作,并供给灵活的布局和交互性。
一、源码分析
跟踪 android:requiresFadingEdge 初始化设定的方位,是在最基本的 View 控件内。当 View 制作时满意特定条件就会用内部的 ScrollabilityCache 制作滚动条、边际淡化等滑动用的元素。
抛开 ScrollabilityCache ,看看 View 的 draw(Canvas canvas) 方法,源代码里写得很清楚:
public void draw(Canvas canvas) {
final int privateFlags = mPrivateFlags;
mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
/*
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
*
* 1. Draw the background
* 2. If necessary, save the canvas' layers to prepare for fading
* 3. Draw view's content
* 4. Draw children
* 5. If necessary, draw the fading edges and restore layers
* 6. Draw decorations (scrollbars for instance)
* 7. If necessary, draw the default focus highlight
*/
.....
if (verticalEdges) {
topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength()));
drawTop = topFadeStrength * fadeHeight > 1.0f;
bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength()));
drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
}
....
}
如果需求制作边际淡化,会多添加第2和第5步的差异
二、自定义ScollerView
既然CoordinatorLayout不支撑边际淡化,是否能够使用ScollerView把它包裹起来,然后动态操控边际淡化显现和隐藏即可。
根据上面的源码分析,咱们能够知道边际淡化是由drawTop、drawBottom..几个变量操控,它是通过getTopFadingEdgeStrength()…这几个方法判断制作长度。那么咱们只需求在自定义控件中重写对应的方法就能使边际淡化,实际使用中还需求动态改变并刷新 View 来准确操控作用。
class MaskScrollView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : ScrollView(context, attrs) {
var isShowEdge:Boolean = false
set(value) {
if (field != value) {
field = value
// 避免getTopFadingEdgeStrength()不调用
invalidate()
}
}
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
return false
}
override fun getTopFadingEdgeStrength(): Float {
return if (isShowEdge) 1.0f else 0f
}
}
- MaskScrollView只作为边际淡化显现的载体,因此不需求处理任何事情onInterceptTouchEvent直接返回false
- getTopFadingEdgeStrength()只会在View的onDraw()方法调用,当isShowEdge改变时确保View的刷新,添加invalidate()
- 如果不需求底部的边际淡化能够直接在getBottomFadingEdgeStrength()返回0f
而监听CoordinatorLayout的滑动能够通过AppBarLayout滑动监听来实现
binding.appBarLayout.addOnOffsetChangedListener(
AppBarLayout.OnOffsetChangedListener { _, verticalOffset ->
binding.maskScrollView.isShowEdge = verticalOffset < 0
}
)