Android recyclerview 无限循环居中并自动向下滚动
描述:这是一个基于recyclerview实现的 Android 无限循环滚动Demo,可自定义item。
项目代码在最后面!!!!跳转到最后
控件效果如下:
此控件为Android 无限循环居中并可以自动向下滚动。
实现功能:
- 上下滚动无限循环(跳转回之前相似的postion)
- 自动滚动
- 利用flex可进行流式内容布局
设计核心:
主要的设计核心是依赖于recyclerview进行设计的,主要通过重写layoutmanager,Adapter,RecyclerView等来实现
核心代码:
CycleFlexManager .java
根据数量进行高度调整
package com.ui.design.view.automeasurelinear.linearmanager;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.flexbox.FlexboxLayoutManager;
/** * 流式布局 */
public class CycleFlexManager extends FlexboxLayoutManager {
private RecyclerView mRecyclerView;
private int mItemViewHeight = 0;
public CycleFlexManager(Context context, RecyclerView recyclerView) {
super(context);
this.mRecyclerView = recyclerView;
}
public CycleFlexManager(Context context, int flexDirection) {
super(context, flexDirection);
}
public CycleFlexManager(Context context, int flexDirection, int flexWrap) {
super(context, flexDirection, flexWrap);
}
public CycleFlexManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
/** * 添加LinearSnapHelper */
@Override
public void onAttachedToWindow(RecyclerView view) {
super.onAttachedToWindow(view);
}
/** * 当滑动停止时触发回调 无限向下滚动 */
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
if (state == 0) {
int topposition = findFirstVisibleItemPosition();
int lastpostion = findLastCompletelyVisibleItemPosition();
Log.e("TEST", "findFirstVisibleItemPosition" + topposition);
Log.e("TEST", "findLastVisibleItemPosition" + lastpostion);
if (lastpostion > getItemCount() - 5) {
//有些View可能转载比较多item 用顶部的postion来指示
int prepostion = lastpostion - getItemCount() / 2;
Log.e("TEST", "childconut" + prepostion);
// View view=findViewByPosition(lastpostion);
scrollToPosition(prepostion + 1); //找到可视图里第一个postion并让他向前移动一半
}
if (topposition == 0) {
int prepostion = topposition + getItemCount() / 2;
Log.e("TEST", "childconut" + prepostion);
scrollToPosition(prepostion-1);
}
}
}
public int getmItemViewHeight() {
if (mItemViewHeight==0){
View view=findViewByPosition(0);
if (view!=null){
measureChildWithMargins(view, 0, 0);
mItemViewHeight = view.getMeasuredHeight();
}
}
return mItemViewHeight;
}
}
AutoPollRecyclerView .java
自动滚动
package com.ui.design.view.automeasurelinear.recyclerview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.ui.design.view.automeasurelinear.linearmanager.CycleFlexManager;
import java.lang.ref.WeakReference;
/** * 中间位置迁移 */
public class AutoPollRecyclerView extends RecyclerView {
private static final long TIME_AUTO_POLL = 16;
AutoPollTask autoPollTask;
private boolean running; //表示是否正在自动轮询
private boolean canRun;//表示是否可以自动轮询
public AutoPollRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
autoPollTask = new AutoPollTask(this);
}
static class AutoPollTask implements Runnable {
private final WeakReference<AutoPollRecyclerView> mReference;
//使用弱引用持有外部类引用->防止内存泄漏
public AutoPollTask(AutoPollRecyclerView reference) {
this.mReference = new WeakReference<>(reference);
}
@Override
public void run() {
AutoPollRecyclerView recyclerView = mReference.get();
if (recyclerView.running && recyclerView.canRun) {
recyclerView.scrollBy(2, 2);
if (!recyclerView.canScrollVertically(5)){
if (recyclerView.getLayoutManager() instanceof CycleFlexManager){
((CycleFlexManager)recyclerView.getLayoutManager()).onScrollStateChanged(0);//向无限循环manager释放不滚动信号 进行位置迁移
}
}
recyclerView.postDelayed(recyclerView.autoPollTask, TIME_AUTO_POLL);
}
}
}
//开启:如果正在运行,先停止->再开启
public void start() {
if (running)
stop();
canRun = true;
running = true;
postDelayed(autoPollTask, TIME_AUTO_POLL);
}
public void stop() {
running = false;
removeCallbacks(autoPollTask);
}
@Override
public boolean onTouchEvent(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
if (running)
stop();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_OUTSIDE:
if (canRun)
start();
break;
}
return super.onTouchEvent(e);
}
private int cycleNum=4;
public int getCycleNum() {
return cycleNum;
}
public void setCycleNum(int cycleNum) {
this.cycleNum = cycleNum;
}
}
AutoMeasureAdapter.java 在Adapter中将size增加 不然无法实现无限循环滚动
package com.ui.design.view.automeasurelinear.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.alibaba.android.arouter.launcher.ARouter;
import com.ui.design.R;
import com.ui.design.main.bean.SelectorBean;
import com.ui.design.view.pickviewselect.view.PickerLayoutManager;
import java.util.List;
/** * 适配器 * tangxianfeng * 2021.12.23 */
public class AutoMeasureAdapter extends RecyclerView.Adapter<AutoMeasureAdapter.SViewHolder> {
private final List<String> mList;
private final Context mContext;
private int mCycleNum=8;//长度重复次数 默认为8
public AutoMeasureAdapter(Context context, List<String> stringList){
this.mContext=context;
this.mList=stringList;
}
@NonNull
@Override
public SViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new SViewHolder(LayoutInflater.from(mContext).inflate(R.layout.automeasure_adapter_item, parent,false));
}
@Override
public void onBindViewHolder(@NonNull SViewHolder holder, int position) {
if (mList == null || mList.size() == 0) {
return;
}
holder.cardname.setText(mList.get(position % mList.size()));
}
@Override
public int getItemCount() {
if (mList == null||mList.size()==0) {
return 0;
}
return mList.size() * mCycleNum;//直接乘
}
static class SViewHolder extends RecyclerView.ViewHolder{
private final TextView cardname;
public SViewHolder(@NonNull View itemView) {
super(itemView);
cardname=(TextView) itemView.findViewById(R.id.card_name);
}
}
public int getmCycleNum() {
return mCycleNum;
}
public void setmCycleNum(int mCycleNum) {
if (mCycleNum%2==1){
mCycleNum++;//保证mCycleNum为2的倍数
}
this.mCycleNum = mCycleNum;
}
}
使用示例:
AutomeasureActivity.java
package com.ui.design.view.automeasurelinear;
import androidx.recyclerview.widget.RecyclerView;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.google.android.flexbox.FlexDirection;
import com.google.android.flexbox.JustifyContent;
import com.ui.design.R;
import com.ui.design.main.base.BaseActivity;
import com.ui.design.main.constants.Constants;
import com.ui.design.utils.RandomValue;
import com.ui.design.view.automeasurelinear.adapter.AutoMeasureAdapter;
import com.ui.design.view.automeasurelinear.linearmanager.CycleFlexManager;
import com.ui.design.view.automeasurelinear.recyclerview.AutoPollRecyclerView;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@Route(path = Constants.AutomeasureActivity)
public class AutomeasureActivity extends BaseActivity {
private List<String> stringList;
@Override
protected int initLayout() {
return R.layout.activity_automeasure;
}
@Override
protected void initView() {
stringList=new ArrayList<>();
for (int i=0;i<50;i++){
stringList.add(RandomValue.getRandomContent());
}
AutoPollRecyclerView recyclerView=findViewById(R.id.auto_center);
CycleFlexManager layoutManager = new CycleFlexManager(this,recyclerView);
layoutManager.setFlexDirection(FlexDirection.ROW);//可设置排列
layoutManager.setJustifyContent(JustifyContent.CENTER);//可设置是否居中
recyclerView.setLayoutManager(layoutManager);
recyclerView.start();
AutoMeasureAdapter autoMeasureAdapter = new AutoMeasureAdapter(this,stringList);
recyclerView.setAdapter(autoMeasureAdapter);
}
@Override
protected void initData() {
}
}
activity_automeasure.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".view.automeasurelinear.AutomeasureActivity">
<include layout="@layout/title_include"/>
<com.ui.design.view.automeasurelinear.recyclerview.AutoPollRecyclerView android:id="@+id/auto_center" android:layout_width="match_parent" android:layout_height="wrap_content" />
</LinearLayout>
项目代码仓库
如果直接复制可能会出现代码缺陷,完整代码请去仓库下载
如果觉得还行,耽误您几秒钟的时间去我的仓库点点star,万一以后用到了呢?
文章评论