当前位置: 首页 > news >正文

浏览器怎么做能不拦截网站浙江省工程建设协会网站

浏览器怎么做能不拦截网站,浙江省工程建设协会网站,兰州手机网站建设,文登城乡建设局网站此前大部分涉及到 RecyclerView 页面的 LayoutManager基本上用系统提供的 LinearLayoutManager 、GridLayoutManager 就能解决#xff0c;但在一些特殊场景上还是需要我们自定义 LayoutManager。之前基本上没有自己写过#xff0c;在网上看各种源码各种文章#xff0c;刚开始…此前大部分涉及到 RecyclerView 页面的 LayoutManager基本上用系统提供的 LinearLayoutManager 、GridLayoutManager 就能解决但在一些特殊场景上还是需要我们自定义 LayoutManager。之前基本上没有自己写过在网上看各种源码各种文章刚开始花了好多时间去理解整体流程因为它们都给我一种非常非常复杂的感觉包括相关的博客文章也是。经过一段时间摸索也慢慢能理解为什么要那么复杂了这的确不是特别容易入门。所以对整体的流程进行了一个拆解尽量原子化一点对自己学习的一个总结也希望能帮助到一部分人能对 LayoutManager 入门。 本文最终实现一个简单的 LinearLayoutManager只支持 VERTICAL方向适合对 LayoutManager 整体流程的学习与理解整体代码分为多个文件每个文件都是对前一段代码的补充方便理解整体项目源码已提交 Github: LayoutManagerGradually代码里面写了很多很多注释如果不想浪费时间可以直接看代码运行跳过这篇文章把每一个 LayoutManager 都跑一下体验结合代码看看。 自定义 LayoutManager 的必要元素 继承 RecyclerView.LayoutManager 并实现 generateDefaultLayoutParams() 方法 重写onLayoutChildren 第一次数据填充的时候数据添加 重写 canScrollHorizontally() 和canScrollVertically()方法设定支持滑动的方向 重写 scrollHorizontallyBy()和scrollVerticallyBy()方法在滑动的时候对屏幕以外的 View 进行回收以及填充即将滑动进入屏幕范围内的 View 进行填充 重写 scrollToPosition()和smoothScrollToPosition()方法支持 其中onLayoutChildren 和 scrollHorizontallyBy/scrollVerticallyBy 是最核心且最复杂的方法这里稍微拎出来讲一下 onLayoutChildren 这个方法类似于自定义 ViewGroup 的 onLayout() 方法RecyclerView 的 LayoutManager.onLayoutChildren 在以下几个时机会被触发 当 RecyclerView 首次附加到窗口时当Adapter 的数据集发生变化当 RecyclerView 被 执行 RequetLayout的时候当 LayoutManager 发生变化时 scrollHorizontallyBy/scrollVerticallyBy 方法的主要作用包括 更新 ItemView 的位置根据传入的垂直滚动距离dy 参数更新子视图在屏幕上的位置。通常调用 offsetChildrenVertical 方法。 回收不可见的 ItemView在滚动过程中一些 ItemView 可能会离开屏幕变得不可见。scrollVerticallyBy 方法需要负责回收这些子视图并将它们放入回收池以便稍后复用。 添加新的 ItemView在滚动过程中新的 ItemView 可能需要显示在屏幕上。scrollVerticallyBy 方法需要从回收池中获取可复用的视图并将它们添加到屏幕上。这通常涉及到调用 RecyclerView.Recycler 的 getViewForPosition 方法。 返回实际滚动距离由于 ItemView 的数量有限滚动可能会受到限制。例如当滚动到列表顶部或底部时滚动可能会停止。在这种情况下实际滚动的距离可能会小于传入的 dy 参数。scrollVerticallyBy 方法需要返回实际滚动的距离以便 RecyclerView 可以正确地更新滚动条和触发滚动事件。 概念就简单讲这么多 talk is cheap show me the code直接看代码理解会比较深刻 逐步实现 要实现一个可用的 LayoutManger 通常我们需要实现以下流程 数据填充并且只需要填充屏幕范围内的 ItemView回收掉屏幕以外的 ItemView屏幕外 ItemView 再回到屏幕后需要重新填充对滑动边界边界进行处理对 scrollToPosition 和 smoothScrollToPosition进行支持 我们不用一上来就实现最终的效果而是一步一步来看看 LayoutManger 是怎么渐渐地变化最终能跑起来的。 0 最简单的 LayoutManager 代码查看MostSimpleLayoutManager我们关注 onLayoutChildren 方法: override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State?) {// 垂直方向的偏移量var offsetTop 0// 实际业务中最好不要这样一次性加载所有的数据这里只是最简单地演示一下整体是如何工作的for (itemIndex in 0 until itemCount) {// 从适配器获取与给定位置关联的视图val itemView recycler.getViewForPosition(itemIndex)// 将视图添加到 RecyclerView 中addView(itemView)// 测量并布局视图measureChildWithMargins(itemView, 0, 0)// 拿到宽高包括ItemDecorationval width getDecoratedMeasuredWidth(itemView)val height getDecoratedMeasuredHeight(itemView)// 对要添加的子 View 进行布局layoutDecorated(itemView, 0, offsetTop, width, offsetTop height)offsetTop height} }上面的代码主要演示了如何利用addView layoutDecorated等方法将 ItemView 添加到 RecyclerView 上。代码可见是 将所有的 ItemView即使它在屏幕上不可见一次性全部加载到了 RecyclerView上 这里一般不这么做只是这里这里只是最简单地演示一下整体是如何工作的。 运行在手机上能看到这样的效果Item数据已经被全部添加到界面上了并且各个方向的滑动都支持。 1 更合理的数据添加方式 代码查看LinearLayoutManager1.kt 对最开始的代码进行优化只在屏幕范围内的区域进行数据的添加这样就不需要一次性将所有数据就添加上去如果 Adapter 的 ItemCount 足够巨大for all addView 的话很容易就 OOM。 override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {// 垂直方向上的的空间大小var remainSpace height - paddingTop//垂直方向的偏移量var offsetTop 0var currentPosition 0while (remainSpace 0 currentPosition state.itemCount) {// 从适配器获取与给定位置关联的视图val itemView recycler.getViewForPosition(currentPosition)// 将视图添加到 RecyclerView 中addView(itemView)// 测量并布局视图measureChildWithMargins(itemView, 0, 0)// 拿到宽高包括ItemDecorationval itemWidth getDecoratedMeasuredWidth(itemView)val itemHeight getDecoratedMeasuredHeight(itemView)// 对要添加的子 View 进行布局layoutDecorated(itemView, 0, offsetTop, itemWidth, offsetTop itemHeight)offsetTop itemHeightcurrentPosition// 可用空间减少remainSpace - itemHeight} }2 对屏幕外的View回收 代码查看LinearLayoutManager2 RecylerView 没有 recycler 怎么行呢当 RecylerView 的 ItemView 滑出屏幕后我们需要对齐进行回收实现的话需要在 scrollVerticallyBy中比较复杂的逻辑就是怎么去判断ItemView 在屏幕以外最后利用removeAndRecycleView方法进行回收 override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler, state: RecyclerView.State?): Int {// 在这里处理上下的滚动逻辑dy 表示滚动的距离// 平移所有子视图offsetChildrenVertical(-dy)// 如果实际滚动距离与 dy 相同返回 dy如果未滚动返回 0recycleInvisibleView(dy, recycler)return dy }/*** 回收掉在界面上看不到的 ItemView** param dy* param recycler*/ private fun recycleInvisibleView(dy: Int, recycler: RecyclerView.Recycler) {val totalSpace orientationHelper.totalSpace// 将要回收View的集合val recycleViews hashSetOfView()// 从下往上滑if (dy 0) {for (i in 0 until childCount) {val child getChildAt(i)!!// 从下往上滑从最上面的 item 开始计算val top getDecoratedTop(child)// 判断最顶部的 item 是否已经完全不可见如何可见那说明底下的 item 也是可见val height top - getDecoratedBottom(child)if (height - top 0) {break}recycleViews.add(child)}} else if (dy 0) { // 从上往下滑for (i in childCount - 1 downTo 0) {val child getChildAt(i)!!// 从上往下滑从最底部的 item 开始计算val bottom getDecoratedBottom(child)// 判断最底部的 item 是否已经完全不可见如何可见那说明上面的 item 也是可见val height bottom - getDecoratedTop(child)if (bottom - totalSpace height) {break}recycleViews.add(child)}}// 真正把 View 移除掉的逻辑for (view in recycleViews) {// [removeAndRecycleView]// 用于从视图层次结构中删除某个视图并将其资源回收以便在需要时重新利用removeAndRecycleView(view, recycler)}recycleViews.clear() }运行在手机上能看到这样的效果滑出屏幕外的ItemView 被回收掉了 3 向上滑动的时View的填充 代码查看LinearLayoutManager3 override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler, state: RecyclerView.State?): Int {// 填充 viewfillView(dy, recycler)// 移动 viewoffsetChildrenVertical(-dy)// 回收 ViewrecycleInvisibleView(dy, recycler)return dy }/*** 填充重新进入屏幕内的 ItemView* getChildCount():childCount- 当前屏幕内RecyclerView展示的 ItemView 数量* getItemCount():itemCount- 最大的 ItemView 数量也就是 Adapter 传递的数据的数量*/ private fun fillView(dy: Int, recycler: RecyclerView.Recycler) {val verticalSpace orientationVerticalHelper.totalSpacevar remainSpace 0var nextFillPosition 0//垂直方向的偏移量var offsetTop 0var offsetLeft 0// 从下往上滑那么需要向底部添加数据if (dy 0) {val anchorView getChildAt(childCount - 1) ?: returnval anchorPosition getPosition(anchorView)val anchorBottom getDecoratedBottom(anchorView)val anchorLeft getDecoratedLeft(anchorView)remainSpace verticalSpace - anchorBottom// 垂直可用的数据为0意外着这时候屏幕底部的位置刚好在最底部的 ItemView 上还需要向上滑动一点点...我们才能添加 Viewif (remainSpace 0) {return}nextFillPosition anchorPosition 1offsetTop anchorBottomoffsetLeft anchorLeftif (nextFillPosition itemCount) {return}} else if (dy 0) { // 从上往下滑那么需要向顶部添加数据//no-op 暂时不实现从上往下滑的底部数据填充}while (remainSpace 0 nextFillPosition itemCount) {// 从适配器获取与给定位置关联的视图val itemView recycler.getViewForPosition(nextFillPosition)// 将视图添加到 RecyclerView 中addView(itemView)// 测量并布局视图measureChildWithMargins(itemView, 0, 0)// 拿到宽高包括ItemDecorationval itemWidth getDecoratedMeasuredWidth(itemView)val itemHeight getDecoratedMeasuredHeight(itemView)// 对要添加的子 View 进行布局相比onLayoutChildren 里面的实现添加了offsetLeft因为我们没有禁止掉 左右的滑动// 试着把 offsetLeft 改成0也就是最原始的样子然后左右上下滑滑你会有意外收获layoutDecorated(itemView, offsetLeft, offsetTop, itemWidth offsetLeft, offsetTop itemHeight)offsetTop itemHeightnextFillPosition// 可用空间减少remainSpace - itemHeight} }运行在手机上能看到这样的效果向上滑动的时候底部陆续有元素填充但向下滑动的时候没有填充数据 4 两个方向的View填充 代码查看LinearLayoutManager4 补齐从上往下滑之后添加的逻辑 private fun fillView(dy: Int, recycler: RecyclerView.Recycler) {val verticalSpace orientationVerticalHelper.totalSpacevar remainSpace 0var nextFillPosition 0//垂直方向的偏移量var offsetTop 0var offsetLeft 0// 从下往上滑那么需要向底部添加数据if (dy 0) {……} else if (dy 0) { // 从上往下滑那么需要向顶部添加数据val anchorView getChildAt(0) ?: returnval anchorPosition getPosition(anchorView)val anchorTop getDecoratedTop(anchorView)offsetLeft getDecoratedLeft(anchorView)remainSpace anchorTop// 垂直可用的数据为0意外着这时候屏幕顶部的位置刚好在最底部的 ItemView 上还需要向下滑动一点点...我们才能添加 Viewif (anchorTop 0) {return}nextFillPosition anchorPosition - 1if (nextFillPosition 0) {return}val itemHeight getDecoratedMeasuredHeight(anchorView)// 新的布局的itemView 的顶部位置应该以 anchorTop - itemHeight 开始offsetTop anchorTop - itemHeight}while (remainSpace 0 ((nextFillPosition itemCount) (nextFillPosition 0))) {// 从适配器获取与给定位置关联的视图val itemView recycler.getViewForPosition(nextFillPosition)// 将视图添加到 RecyclerView 中k从顶部添加的话需要加到最前的位置if (dy 0) {addView(itemView)} else {addView(itemView, 0)}……if (dy 0) {offsetTop itemHeightnextFillPosition} else {offsetTop - itemHeightnextFillPosition--}// 可用空间减少remainSpace - itemHeight}运行在手机上能看到这样的效果向上或者滑动的时候底部陆续都有元素填充 5 对顶部和底部滑动边界处理 代码查看LinearLayoutManager5 对于前面的实现会发现会不停地下滑或者上滑会留出来巨大的空白。这里对填充 View 的逻辑进行改造需要进行边界检测。 override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler, state: RecyclerView.State?): Int {// 填充 viewval adjustedDy fillView(dy, recycler)// 移动 viewoffsetChildrenVertical(-adjustedDy)// 回收 ViewrecycleInvisibleView(adjustedDy, recycler)// 由于需要对边界进行限制所以需要对原始的 dy 进行修正这里不再直接返回 dyreturn adjustedDy } 这里的整体注释我写在了代码里面可以看图稍微理解一下以向上滑动为例假设这一次滑动的距离非常非常大(想象成10000像素)如果直接滑动的话我们有50个元素每个元素高度100像素最大高度也只有50x1005000那么滑动后一定会留下大量空区域。需要对当前传入的这 10000 像素做调整只给到可滑动的最大距离如果不能滑动了就返回0。 运行在手机上能看到这样的效果向上或者滑动的时候达到最大的位置时候是不能再滑动的。 6 实现 scrollToPosition 代码查看LinearLayoutManager6 到这里这个 LinearLayoutManager 看着已经能正常运行了但一般还需要支持scrollToPosition 和 smoothScrollToPositio private var mPendingScrollPosition RecyclerView.NO_POSITIONoverride fun scrollToPosition(position: Int) {super.scrollToPosition(position)if (position 0 || position itemCount) {return}mPendingScrollPosition positionrequestLayout() }override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {……var currentPosition 0if (mPendingScrollPosition ! RecyclerView.NO_POSITION) {currentPosition mPendingScrollPosition}while (remainSpace 0 currentPosition state.itemCount) {…… // 填充View 的逻辑} }scrollToPosition 的实现比较简单如上代码所示在 scrollToPosition 的时候记录一次目标position再 requestLayout 一波还记得之前有提到过onLayoutChildren 会在 requestLayout 的时候调用一次于是再将onLayoutChildren逻辑改写不再从第0个元素开始而是从目标位置进行布局。 运行在手机上能看到这样的效果点击 scrollTo30 将会滑动到 第30个位置。 7 实现 smoothScrollToPosition 代码查看LinearLayoutManager7 要实现自定义的 smoothScrollToPosition 动画效果这一块如果要完全自己实现的话比较复杂可以直接使用系统提供的 LinearSmoothScroller改造,也可以继承 RecyclerView.SmoothScroller 自定义也可以完全不使用 SmoothScroller 照着 SmoothScroller 的实现使用类似 ValueAnimator 自定义动画添加动画 UpdateListener在 onAnimationUpdate 的时候动态计算布局从而实现滑动动画,这里拿 LinearSmoothScroller 举例: override fun smoothScrollToPosition(recyclerView: RecyclerView,state: RecyclerView.State,position: Int ) {if (position itemCount || position 0) {return}val scroller: LinearSmoothScroller object : LinearSmoothScroller(recyclerView.context) {/*** 这个方法用于计算滚动到目标位置所需的滚动向量。滚动向量是一个二维向量包含水平和垂直方向上的滚动距离** param targetPosition 滑动的目标位置* return 返回一个 PointF 对象表示滚动向量。* PointF.x 表示水平方向上的滚动距离* PointF.y 表示垂直方向上的滚动距离*/override fun computeScrollVectorForPosition(targetPosition: Int): PointF {// 查找到屏幕里显示的第 1 个元素与val firstChildPos getPosition(getChildAt(0)!!)val direction if (targetPosition firstChildPos) -1 else 1// x 左右滑动由于我们只实现了垂直的滑动所以 x方向为0即可// 整数代表正向移动负数代表反向移动这里的数值大小不重要源码里面最终都会 normalize 归一化处理return PointF(0f, direction.toFloat())}/*** 计算每像素速度** param displayMetrics* return 返回每一像素的耗时单位ms假设返回值是1.0 代表着1ms 内会滑动 1像素1s会滑动1000像素*/override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics?): Float {return super.calculateSpeedPerPixel(displayMetrics)}/*** 滑动速度的插值实现滑动速度随着滑动时间的变化** param dx* return*/override fun calculateTimeForDeceleration(dx: Int): Int {return super.calculateTimeForDeceleration(dx)}// 很多方法可以使用不再一一列举// ...}scroller.targetPosition position// 执行默认动画的逻辑startSmoothScroll(scroller) }运行在手机上能看到这样的效果点击 smoothScrollTo30 将会有个动画效果滑动到第30个位置。 以上基本上一个自定义 LayoutManager 的雏形就已经完成了虽然只实现了一个方向的滑动但是其原理都是一样的剩下的就是各种细节的打磨了可以加各种自己想要的效果比如指定位置 放大一定的系数或者更炫酷的滑动动画… 总结 本文主要整理了自定义 LayoutManager 的必要元素以及其核心方法 scrollHorizontallyBy/scrollVerticallyBy、onLayoutChildren 的作用与调用时机接下对实现一个简单的 LinearLayoutManger 进行逻辑拆解从最简单的不滑动回收和填充以及不含滑动边界检测到最终一个具备基本功能的 LinearLayoutManger 源码https://github.com/VomPom/LayoutManagerGradually 参考 《看完这篇文章你还不会自定义LayoutManager我吃X》 《/LayoutManager分析与实践》 Building a RecyclerView LayoutManager – Part 1
http://www.sczhlp.com/news/207474/

相关文章:

  • 免费的软件网站网站开发人员没有按照设计开发
  • 网站开发问题及解决厦门旅游网站
  • 网站icp备案新规做网站 租服务器吗
  • 做淘宝一件代发的网站网站建设菜鸟教程
  • 网站主机测速开发手机端网站模板
  • 沈阳企业自助建站网络管理软件免费
  • 服装电子商务网站建设与实现上海商城网站开发
  • 福州什么推广网站好网站建设常熟
  • 泰安网站建设个人工作室网站的服务有哪些
  • 新翼设计网站建设公司新网域名自助管理平台
  • 一家专门做衣服的网站东营胡瑞琦
  • 如何建设网站app桂林论坛网网站电话
  • 河源市做网站郑州的建设网站有哪些手续
  • 体检中心网站建设方案wordpress 模板命名
  • 宁波做网站优化多少钱wordpress免邮箱验证
  • 青岛网站建设方案咨询太原小程序制作
  • 网站建设发展方向怎么写注册公司要多久下来
  • 建设报名系统官方网站做网站需要去哪里备案
  • 电脑课做网站所需的软件建立网站的顺序
  • 西安网站建设公司哪家好wordpress编辑器还原
  • 2025 年盖板源头厂家最新推荐榜单:电力 / 隧道 / 电缆沟等多场景适用品牌优选,解析原材料采购与成本控制要点
  • win
  • 2025 年真空炉制造厂家最新推荐排行榜:涵盖高温烧结真空炉 / 真空退火炉 / 智能铍铜真空炉,助力企业精准选型
  • 2025 年最新推荐排水沟厂家排行榜:聚焦树脂 / 线性 / 树脂混凝土 / 成品 / U 型排水沟优质企业
  • Kubernetes日志管理:使用Loki进行日志采集
  • 域名 放别人网站网站宽度多少合适
  • 网站需要多大的空间做网站网站庄家
  • 四川建设银行手机银行下载官方网站下载南宁网站建设蓝云
  • 网站域名查询系统终身免费vps
  • 温州网站建设方案外包wordpress导航彩条