常见知识点总结

9 阅读2分钟

Flow

  • replay 设置为 BufferOverflow.DROP_LATEST 时 , replay 必须大于 0,replay 为0 时 ,必须为suspend,BufferOverflow.DROP_LATEST 会crash
  • StateFlow 具备自动去重功能 , ShareFlow 不具备去重功能
  • replay 必须大于0 时候 , tryEmit 才会有效果
  • 任何场景下 onCompletion 均会调用 ,无论是 throw 还是 cancel , 都会调用, catch 只会catch 自定义的异常

LinearSmoothScroller

/**  
* @param offset 根据 snapPreference 的值作为参考系,offset 大于表示向参考系正方向移动距离,负值表示向参考系负方向移动的距离  
* @param millisecondsPerInch 滑动每英寸所需要的时间  
* @param snapPreference  
* SNAP_TO_START 目标view 滚动到与 RecyclerView 左对齐, 以RecyclerView左侧侧为参考系, offset 大于0,示目标view以 RecyclerView左对齐 + 滑出 offset ,offset 小于 0 时,示目标view以 RecyclerView左对齐,  
* 向左侧多滑出 offset  
* SNAP_TO_END 目标view 滚动到与 RecyclerView右对齐 以RecyclerView右侧为参考系,右边大于0, 左侧小于0, offset大于0 时表示目标view以 RecyclerView右对齐且向右多出 offset  
* offset小于0 表示像左侧多划出 offset  
*  
*/  
private fun RecyclerView.smoothScrollToPositionWithOffset(position: Int, offset: Int, millisecondsPerInch: Float = 0f, snapPreference: Int = SNAP_TO_START) {  
    val itemCount = adapter?.itemCount ?: -1  
    if (position < 0 || position >= itemCount) {  
        return  
    }  
    val linearSmoothScroller = object : LinearSmoothScroller(context) {  
            override fun onTargetFound(targetView: View, state: RecyclerView.State, action: Action) {  
                super.onTargetFound(targetView, state, action)  
                val dx = calculateDxToMakeVisible(targetView, snapPreference)  
                val dy = calculateDyToMakeVisible(targetView, snapPreference)  
                val distance = sqrt((dx * dx + dy * dy).toDouble()).toInt()  
                val time = calculateTimeForDeceleration(distance)  
                if (time > 0) {  
                    action.update(-dx - offset, -dy - offset, time, mDecelerateInterpolator)  
                }  
            }  
  
            override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float {  
                return if (millisecondsPerInch > 0) {  
                    millisecondsPerInch / displayMetrics.densityDpi  
                } else {  
                    super.calculateSpeedPerPixel(displayMetrics)  
                }  
            }  
   }  
   linearSmoothScroller.targetPosition = position  
   layoutManager?.startSmoothScroll(linearSmoothScroller)  
}

ViewPager预加载位置计算

var currentState = ViewPager.SCROLL_STATE_IDLE  
viewPager.addOnPageChangeListener(object : SimpleOnPageChangeListener() {  
    override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {  
        if (currentState == ViewPager.SCROLL_STATE_DRAGGING) {  
            val scrollX = viewPager.scrollX  
            val pageStartScrollX = viewPager.currentItem * viewPager.width  
            if (scrollX < pageStartScrollX) {  
                // 左侧漏出  
                viewPager.currentItem - 1  
            } else if (scrollX > pageStartScrollX) {  
                // 右侧漏出  
                viewPager.currentItem + 1  
            }  
        }  
    }  
  
    override fun onPageScrollStateChanged(state: Int) {  
        currentState = state  
    }  
})  
viewPager.post {  
    // post 是为了确保数据的渲染和绑定是从position 0 开始 ,可以确保position 0 开始 viewPager.scrollX 也是从 0开始  
    // 否则 viewPager.scrollX 可能会以 setCurrentItem 设置的为参考系锚点,scrollX == 0 锚点左侧的 小于 0 锚点右侧的大于 0  
    // 导致计算预加载失败  
    viewPager.setCurrentItem(4, false)  
}