wordpress主题momo,阳江网站seo公司,网站维护与建设,免费网站空间免费主机在第一篇中已经讲过#xff0c;LayoutManager主要用于布局其中的Item#xff0c;在LayoutManager中能够对每个Item的大小#xff0c;位置进行更改#xff0c;将它放在我们想要的位置#xff0c;在很多优秀的效果中#xff0c;都是通过自定义LayoutManager来实现的#x… 在第一篇中已经讲过LayoutManager主要用于布局其中的Item在LayoutManager中能够对每个Item的大小位置进行更改将它放在我们想要的位置在很多优秀的效果中都是通过自定义LayoutManager来实现的比如Github: https://github.com/dongjunkun/RecyclerViewAccentFirst可以看到效果非常棒通过这一节的学习大家也就理解了自定义LayoutManager的方法然后再理解这些控件的代码就不再难了。在这节中我们先自己制作一个LinearLayoutManager来看下如何自定义LayoutManager下节中我们会通过自定义LayoutManager来制作第一个滚轮翻页的效果。自定义CustomLayoutManager先生成一个类CustomLayoutManager派生自LayoutManager:public class CustomLayoutManager extends LayoutManager { Override public LayoutParams generateDefaultLayoutParams() { return null; }}当我们派生自LayoutManager时会强制让我们生成一个方法generateDefaultLayoutParams。这个方法就是RecyclerView Item的布局参数换种说法就是RecyclerView 子 item 的 LayoutParameters若是想修改子Item的布局参数(比如宽/高/margin/padding等等)那么可以在该方法内进行设置。一般来说没什么特殊需求的话则可以直接让子item自己决定自己的宽高即可(wrap_content)。public class CustomLayoutManager extends LayoutManager { Override public LayoutParams generateDefaultLayoutParams() { return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT, RecyclerView.LayoutParams.WRAP_CONTENT); }}如果这时候我们把上节demo中LinearLayoutManager替换下public class LinearActivity extends AppCompatActivity { private ArrayList mDatas new ArrayList();Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView(R.layout.activity_linear); ………… RecyclerView mRecyclerView (RecyclerView) findViewById(R.id.linear_recycler_view); mRecyclerView.setLayoutManager(new CustomLayoutManager()); RecyclerAdapter adapter new RecyclerAdapter(this, mDatas); mRecyclerView.setAdapter(adapter); } …………}运行一下发现页面完全空白我们说过所有的Item的布局都是在LayoutManager中处理的很明显我们目前在CustomLayoutManager中并没有布局任何的Item。当然没有Item出现了。onLayoutChildren()在LayoutManager中所有Item的布局都是在onLayoutChildren()函数中处理的所以我们在CustomLayoutItem中添加onLayoutChildren()函数Overridepublic void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { //定义竖直方向的偏移量 int offsetY 0; for (int i 0; i View view recycler.getViewForPosition(i); addView(view); measureChildWithMargins(view, 0, 0); int width getDecoratedMeasuredWidth(view); int height getDecoratedMeasuredHeight(view); layoutDecorated(view, 0, offsetY, width, offsetY height); offsetY height; }}在这个函数中我主要做了两个事第一把所有的item所对应的view加进来for (int i 0; i View view recycler.getViewForPosition(i); addView(view); …………}第二把所有的Item摆放在它应在的位置public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { //定义竖直方向的偏移量 int offsetY 0; for (int i 0; i ………… measureChildWithMargins(view, 0, 0); int width getDecoratedMeasuredWidth(view); int height getDecoratedMeasuredHeight(view); layoutDecorated(view, 0, offsetY, width, offsetY height); offsetY height; }}measureChildWithMargins(view, 0, 0);函数测量这个View并且通过getDecoratedMeasuredWidth(view)得到测量出来的宽度需要注意的是通过getDecoratedMeasuredWidth(view)得到的是itemdecoration的总宽度。如果你只想得到view的测量宽度通过View.getMeasuredWidth()就可以得到了。然后通过layoutDecorated()函数将每个item摆放在对应的位置每个Item的左右位置都是相同的从左侧x0开始摆放只是y的点需要计算。所以这里有一个变量offsetY用以累加当前Item之前所有item的高度。从而计算出当前item的位置。这个部分难度不大就不再细讲了。在此之后我们再运行程序会发现现在item显示出来了添加滚动效果但是现在还不能滑动如果我们要给它添加上滑动需要修改两个地方Overridepublic boolean canScrollVertically() { return true;}Overridepublic int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { // 平移容器内的item offsetChildrenVertical(-dy); return dy;}我们通过在canScrollVertically()中return true使LayoutManager具有垂直滚动的功能。然后scrollVerticallyBy中接收每次滚动的距离dy。如果你想使LayoutManager具有横向滚动的功能可以通过在canScrollHorizontally()中return true;这里需要注意的是,在scrollVerticallyBy中dy表示手指在屏幕上每次滑动的位移。当手指由下往上滑时dy0当手指由上往下滑时dy0当手指向上滑动时我们需要让所有子Item向上移动向上移动明显是需要减去dy的。所以大家经过测试也可以发现让容器内的item移动-dy距离,才符合生活习惯。在LayoutManager中我们可以通过public void offsetChildrenVertical(int dy)函数来移动RecycerView中的所有item。现在我们再运行一下这里虽然实现了滚动但是Item到顶之后仍然可以滚动这明显是不对的我们需要在滚动时添加判断如果到顶了或者到底了就不让它滚动了。判断到顶判断到顶相对比较容易我们只需要把所有的dy相加如果小于0就表示已经到顶了。就不让它再移动就行代码如下private int mSumDy 0;Overridepublic int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { int travel dy; //如果滑动到最顶部 if (mSumDy dy 0) { travel -mSumDy; } mSumDy travel; // 平移容器内的item offsetChildrenVertical(-travel); return dy;}在这段代码中通过变量mSumDy 保存所有移动过的dy如果当前移动的距离0那么就不再累加dy直接让它移动到y0的位置因为之前已经移动的距离是mSumdy; 所以计算方法为travelmSumdy 0; travel -mSumdy所以要将它移到y0的位置需要移动的距离为-mSumdy效果如下图所示从效果图中可以看到现在在到顶时就不会再移动了。下面再来看看到底的问题。判断到底判断到底的方法其实就是我们需要知道所有item的总高度用总高度减去最后一屏的高度就是到底的时的偏移值如果大于这个偏移值就说明超过底部了。所以我们首先需要得到所有item的总高度我们知道在onLayoutChildren中会测量所有的item并且对每一个item布局所以我们只需要在onLayoutChildren中将所有item的高度相加就可以得到所有Item的总高度了。private int mTotalHeight 0;public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { //定义竖直方向的偏移量 int offsetY 0; for (int i 0; i View view recycler.getViewForPosition(i); addView(view); measureChildWithMargins(view, 0, 0); int width getDecoratedMeasuredWidth(view); int height getDecoratedMeasuredHeight(view); layoutDecorated(view, 0, offsetY, width, offsetY height); offsetY height; } //如果所有子View的高度和没有填满RecyclerView的高度 // 则将高度设置为RecyclerView的高度 mTotalHeight Math.max(offsetY, getVerticalSpace());}private int getVerticalSpace() { return getHeight() - getPaddingBottom() - getPaddingTop();}getVerticalSpace()函数可以得到RecyclerView用于显示Item的真实高度。而相比上面的onLayoutChildren这里只添加了一句代码mTotalHeight Math.max(offsetY, getVerticalSpace());这里只所以取最offsetY和getVerticalSpace()的最大值是因为offsetY是所有item的总高度而当item填不满RecyclerView时offsetY应该是比RecyclerView的真正高度小的而此时的真正的高度应该是RecyclerView本身所设置的高度。接下来就是在scrollVerticallyBy中判断到底并处理了public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { int travel dy; //如果滑动到最顶部 if (mSumDy dy 0) { travel -mSumDy; } else if (mSumDy dy mTotalHeight - getVerticalSpace()) { travel mTotalHeight - getVerticalSpace() - mSumDy; } mSumDy travel; // 平移容器内的item offsetChildrenVertical(-travel); return dy;}mSumDy dy mTotalHeight - getVerticalSpace()中mSumDy dy表示当前的移动距离mTotalHeight - getVerticalSpace()表示当滑动到底时滚动的总距离当滑动到底时此次的移动距离要怎么算呢 算法如下travel mSumDy mTotalHeight - getVerticalSpace();即此将将要移动的距离加上之前的总移动距离应该是到底的距离。 travel mTotalHeight - getVerticalSpace() - mSumDy;现在再运行一下代码可以看到这时候的垂直滑动列表就完成了从列表中可以看出现在到顶和到底可以继续滑动的问题就都解决了。下面贴出完整的CustomLayoutManager代码供大家参考package com.example.myrecyclerview;import android.util.Log;import android.view.View;import androidx.recyclerview.widget.RecyclerView;public class CustomLayoutManager extends RecyclerView.LayoutManager { Override public RecyclerView.LayoutParams generateDefaultLayoutParams() { return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT, RecyclerView.LayoutParams.WRAP_CONTENT); } private int mTotalHeight 0; public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { //定义竖直方向的偏移量 int offsetY 0; for (int i 0; i View view recycler.getViewForPosition(i); addView(view); measureChildWithMargins(view, 0, 0); int width getDecoratedMeasuredWidth(view); int height getDecoratedMeasuredHeight(view); layoutDecorated(view, 0, offsetY, width, offsetY height); offsetY height; } //如果所有子View的高度和没有填满RecyclerView的高度 // 则将高度设置为RecyclerView的高度 mTotalHeight Math.max(offsetY, getVerticalSpace()); } private int getVerticalSpace() { return getHeight() - getPaddingBottom() - getPaddingTop(); } Override public boolean canScrollVertically() { return true; } private int mSumDy 0; Override public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { int travel dy; //如果滑动到最顶部 if (mSumDy dy 0) { travel -mSumDy; } else if (mSumDy dy mTotalHeight - getVerticalSpace()) { travel mTotalHeight - getVerticalSpace() - mSumDy; } mSumDy travel; // 平移容器内的item offsetChildrenVertical(-travel); return dy; }}完---END---推荐阅读Android | 自定义上拉抽屉组合动画效果重磅Gradle 6.6 发布大幅提升性能Flutter(Flare) 最有趣用户交互动画没有之一怒爬某破Hub站资源只为撸这个鉴黄平台Flutter 10天高仿大厂App及小技巧积累总结阿里巴巴官方最新Redis开发规范涉嫌侵害用户权益这101款App被点名更文不易点个“在看”支持一下?