Android进阶之路 - RecyclverView无限自动水平滚动
需求场景来源于用户长时间未操作屏幕,唤出的屏保界面,屏保界面效果底部为横向滚动商品小图,上方为商品大图 ~
友情提示:关于如何监听用户长时间未操作屏幕的功能实现可 GO → go 此处 ~
这应该是去年做的一个简单功能,最初是直接套用的别人代码,但是使用中发现存在一些bug和不足,同时适用场景有限,所以特在修改、补全后记录于此 ~
- 基础版
- 业务版
- 全面版
Look here ~
基础版
此版已具备屏保的基本功能,可直接使用~
功能:
- 支持底部商品无限横向滚动
ps:主要在Adapter getItemCount时使用了Integer.MAX_VALUE,性能可能不太好 ~ - 支持滚动期间动态更换大图
- 支持用户手动滑动底部商品图操作
ps:之前存在的一些bug 均以解决 ~
ScreenAdapter
package nk.com.carouseldemo;import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;import java.util.List;/*** @author MrLiu* @date 2020/12/10* desc */
public class ScreenAdapter extends RecyclerView.Adapter<ScreenAdapter.ViewHolder> {private Context context;private List<Integer> mDataList;private OnItemClickListener onItemClickListener;public ScreenAdapter(Context context, List<Integer> dataList) {this.context = context;this.mDataList = dataList;}@Overridepublic int getItemCount() {return Integer.MAX_VALUE;}@Overridepublic ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View view = LayoutInflater.from(context).inflate(R.layout.item_screen, parent, false);final ViewHolder vh = new ViewHolder(view);return vh;}@Overridepublic void onBindViewHolder(ViewHolder holder, int position) {int newPos = position % mDataList.size();holder.mDisplay.setImageResource(mDataList.get(newPos));holder.itemView.setTag(position);}class ViewHolder extends RecyclerView.ViewHolder {ImageView mDisplay;public ViewHolder(View itemView) {super(itemView);mDisplay = itemView.findViewById(R.id.iv_display);}}
}
item_screen - 可不同
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="#4CA9EE"android:orientation="vertical"><ImageViewandroid:id="@+id/iv_display"android:layout_width="50dp"android:layout_height="50dp"android:layout_marginTop="5dp"android:layout_marginBottom="5dp"android:padding="5dp"tools:src="@mipmap/ic_launcher" /></LinearLayout>
MainActivity
package nk.com.carouseldemo;import android.annotation.SuppressLint;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;import java.util.ArrayList;
import java.util.List;public class MainActivity extends AppCompatActivity {ImageView mDisplay;RecyclerView mBottomRv;//此处数据源为项目内的图片,不可套用private Integer[] mImgIds = {R.mipmap.banner_1, R.mipmap.banner_2, R.mipmap.banner_3};private List<Integer> imgLists;private ScreenAdapter screenAdapter;private Handler mHandler = new Handler();private LinearLayoutManager layoutManager;private int oldItem = 0;Runnable scrollRunnable = new Runnable() {@Overridepublic void run() {mBottomRv.scrollBy(1, 0);int firstItem = layoutManager.findFirstVisibleItemPosition();if (firstItem != oldItem && firstItem > 0) {oldItem = firstItem;mDisplay.setImageResource(imgLists.get(oldItem % imgLists.size()));}mHandler.postDelayed(scrollRunnable, 10);}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mDisplay = findViewById(R.id.iv_display);mBottomRv = findViewById(R.id.rv_bottom_screen);initData();}public void initData() {//模拟数据源imgLists = new ArrayList<>();for (int i = 0; i < mImgIds.length; i++) {imgLists.add(mImgIds[i]);}//小优化:正常开发中一般为了用户体验初始的时候先手动加载第一个视图mDisplay.setImageResource(imgLists.get(0));screenAdapter = new ScreenAdapter(this, imgLists);layoutManager = new LinearLayoutManager(this);layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);mBottomRv.setLayoutManager(layoutManager);mBottomRv.setAdapter(screenAdapter);mBottomRv.setOnTouchListener(new View.OnTouchListener() {@SuppressLint("ClickableViewAccessibility")@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:Log.e("tag", "down");mHandler.removeCallbacks(scrollRunnable);break;case MotionEvent.ACTION_MOVE:Log.e("tag", "move");int firstItem = layoutManager.findFirstVisibleItemPosition();if (firstItem != oldItem && firstItem >= 0) {oldItem = firstItem;mDisplay.setImageResource(imgLists.get(oldItem % imgLists.size()));}break;case MotionEvent.ACTION_UP:Log.e("tag", "up");mHandler.postDelayed(scrollRunnable, 10);break;}return false;}});}@Overrideprotected void onResume() {super.onResume();mHandler.postDelayed(scrollRunnable, 10);}@Overrideprotected void onStop() {super.onStop();mHandler.removeCallbacks(scrollRunnable);}
}
activity_main
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"><ImageViewandroid:id="@+id/iv_display"android:layout_width="match_parent"android:layout_height="0dp"android:scaleType="fitXY"android:src="@mipmap/ic_launcher_round"app:layout_constraintBottom_toTopOf="@+id/rv_bottom_screen"app:layout_constraintTop_toTopOf="parent" /><android.support.v7.widget.RecyclerViewandroid:id="@+id/rv_bottom_screen"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintTop_toBottomOf="@+id/iv_display" /></android.support.constraint.ConstraintLayout>
业务版
相比基础版,此版本功能在屏保效果中更常见一些,主要体现在用户触碰屏保页即可执行相关操作
功能:
- 支持底部商品无限横向滚动
- 支持滚动期间动态更换大图
不支持用户手动滑动底部商品图操作,取而代之的是只要用户触摸屏幕即执行相关操作
功能方面具备基础版中的所有功能,但因onTouch机制问题,在上层事件已经实现了拦截,体现在用户只要触碰屏幕就会执行相关操作,所以针对于RevyclerView的onTouch监听意义不大 ~
实现方面项目版和基础版大部分是相同的,不同点主要在于重写dispatchTouchEvent 事件,记得RecycleView的onTouch内别直接消耗掉事件~
实现过程
MainActivity
package nk.com.carouseldemo;import android.annotation.SuppressLint;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;import java.util.ArrayList;
import java.util.List;public class MainActivity extends AppCompatActivity {ImageView mDisplay;RecyclerView mBottomRv;//此处数据源为项目内的图片,不可套用private Integer[] mImgIds = {R.mipmap.banner_1, R.mipmap.banner_2, R.mipmap.banner_3};private List<Integer> imgLists;private ScreenAdapter screenAdapter;private Handler mHandler = new Handler();private LinearLayoutManager layoutManager;private int oldItem = 0;Runnable scrollRunnable = new Runnable() {@Overridepublic void run() {mBottomRv.scrollBy(1, 0);int firstItem = layoutManager.findFirstVisibleItemPosition();if (firstItem != oldItem && firstItem > 0) {oldItem = firstItem;mDisplay.setImageResource(imgLists.get(oldItem % imgLists.size()));}mHandler.postDelayed(scrollRunnable, 10);}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mDisplay = findViewById(R.id.iv_display);mBottomRv = findViewById(R.id.rv_bottom_screen);initData();}public void initData() {//模拟数据源imgLists = new ArrayList<>();for (int i = 0; i < mImgIds.length; i++) {imgLists.add(mImgIds[i]);}//小优化:正常开发中一般为了用户体验初始的时候先手动加载第一个视图mDisplay.setImageResource(imgLists.get(0));screenAdapter = new ScreenAdapter(this, imgLists);layoutManager = new LinearLayoutManager(this);layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);mBottomRv.setLayoutManager(layoutManager);mBottomRv.setAdapter(screenAdapter);mBottomRv.setOnTouchListener(new View.OnTouchListener() {@SuppressLint("ClickableViewAccessibility")@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:Log.e("tag", "down");mHandler.removeCallbacks(scrollRunnable);break;case MotionEvent.ACTION_MOVE:Log.e("tag", "move");int firstItem = layoutManager.findFirstVisibleItemPosition();if (firstItem != oldItem && firstItem >= 0) {oldItem = firstItem;mDisplay.setImageResource(imgLists.get(oldItem % imgLists.size()));}break;case MotionEvent.ACTION_UP:Log.e("tag", "up");mHandler.postDelayed(scrollRunnable, 10);break;}return false;}});}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {if (ev.getAction() == MotionEvent.ACTION_DOWN) {// 一般操作习惯是用户点击屏保即跳转首页 ~ 具体看个人需求
// Intent intent = new Intent(this, MainActivity.class);
// intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
// startActivity(intent);
// onBackPressed();Log.e("tag", "跳转首页");return true;}return super.dispatchTouchEvent(ev);}@Overrideprotected void onResume() {super.onResume();mHandler.postDelayed(scrollRunnable, 10);}@Overrideprotected void onStop() {super.onStop();mHandler.removeCallbacks(scrollRunnable);}
}
全面版
基本兼容基础版与业务版,唯一不同在于将业务版中触摸屏幕就关闭屏保的功能移植到了大图的事件上(大图的事件自己写咯 ~),这样就可以适用更多的场景咯 ~
功能:
- 支持底部商品无限横向滚动
- 支持滚动期间动态更换大图
- 支持用户手动滑动底部商品图操作
- 支持用户底部商品的点击事件
ScreenAdapter
package nk.com.carouseldemo;import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;import java.util.List;/*** @author MrLiu* @date 2020/12/10* desc*/
public class ScreenAdapter extends RecyclerView.Adapter<ScreenAdapter.ViewHolder> {private Context context;private List<Integer> mDataList;private OnItemClickListener onItemClickListener;public ScreenAdapter(Context context, List<Integer> dataList) {this.context = context;this.mDataList = dataList;}@Overridepublic int getItemCount() {return Integer.MAX_VALUE;}@Overridepublic ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {final View view = LayoutInflater.from(context).inflate(R.layout.item_screen, parent, false);final ViewHolder vh = new ViewHolder(view);view.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {onItemClickListener.onItemClick(vh.getPosition());}});return vh;}@Overridepublic void onBindViewHolder(ViewHolder holder, int position) {int newPos = position % mDataList.size();holder.mDisplay.setImageResource(mDataList.get(newPos));holder.itemView.setTag(position);}class ViewHolder extends RecyclerView.ViewHolder {ImageView mDisplay;public ViewHolder(View itemView) {super(itemView);mDisplay = itemView.findViewById(R.id.iv_display);}}public void setOnItemClickListener(OnItemClickListener listener) {this.onItemClickListener = listener;}interface OnItemClickListener {void onItemClick(int position);}
}
MainActivity
package nk.com.carouseldemo;import android.annotation.SuppressLint;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;import java.util.ArrayList;
import java.util.List;public class MainActivity extends AppCompatActivity {ImageView mDisplay;RecyclerView mBottomRv;private Integer[] mImgIds = {R.mipmap.banner_1, R.mipmap.banner_2, R.mipmap.banner_3};private List<Integer> imgLists;private ScreenAdapter screenAdapter;private Handler mHandler = new Handler();private LinearLayoutManager layoutManager;private int oldItem = 0;Runnable scrollRunnable = new Runnable() {@Overridepublic void run() {mBottomRv.scrollBy(1, 0);int firstItem = layoutManager.findFirstVisibleItemPosition();if (firstItem != oldItem && firstItem > 0) {oldItem = firstItem;mDisplay.setImageResource(imgLists.get(oldItem % imgLists.size()));}mHandler.postDelayed(scrollRunnable, 10);}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mDisplay = findViewById(R.id.iv_display);mBottomRv = findViewById(R.id.rv_bottom_screen);initData();screenAdapter.setOnItemClickListener(new ScreenAdapter.OnItemClickListener() {@Overridepublic void onItemClick(int position) {Log.e("tag", "position=" + position);//因为使用的是MAX_VALUE,所以要获得真实position要记得 取% ~Log.e("tag", "position=" + position % imgLists.size());}});}public void initData() {//模拟数据源imgLists = new ArrayList<>();for (int i = 0; i < mImgIds.length; i++) {imgLists.add(mImgIds[i]);}//小优化:正常开发中一般为了用户体验初始的时候先手动加载第一个视图mDisplay.setImageResource(imgLists.get(0));screenAdapter = new ScreenAdapter(this, imgLists);layoutManager = new LinearLayoutManager(this);layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);mBottomRv.setLayoutManager(layoutManager);mBottomRv.setAdapter(screenAdapter);mBottomRv.setOnTouchListener(new View.OnTouchListener() {@SuppressLint("ClickableViewAccessibility")@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:Log.e("tag", "down");break;case MotionEvent.ACTION_MOVE:Log.e("tag", "move");mHandler.removeCallbacks(scrollRunnable);int firstItem = layoutManager.findFirstVisibleItemPosition();if (firstItem != oldItem && firstItem >= 0) {oldItem = firstItem;mDisplay.setImageResource(imgLists.get(oldItem % imgLists.size()));}break;case MotionEvent.ACTION_UP:Log.e("tag", "up");mHandler.postDelayed(scrollRunnable, 10);break;}return false;}});}@Overrideprotected void onResume() {super.onResume();mHandler.postDelayed(scrollRunnable, 10);}@Overrideprotected void onStop() {super.onStop();mHandler.removeCallbacks(scrollRunnable);}
}
Android进阶之路 - RecyclverView无限自动水平滚动相关推荐
- Android进阶之路 - 解决部分手机拍照之后图片被旋转的问题
这几天犯了一个错误,初期想着甩锅给后台的- 但还好及时发现了是自身的问题~ 关联文章 Android基础进阶 - 调用拍照.获取图片(基础) Android基础进阶 - 获取.调用相册内图片(基础) ...
- Android进阶之路 - 批量下载、缓存图片、视频
之前已经记录过,批量下载图片和缓存本地的方式,此篇主要记录批量下载图片.视频,同时缓存在本地的功能实现 关联篇 Android进阶之路 - 批量下载.缓存图片 Android进阶之路 - 批量下载.缓 ...
- Android进阶之路 - 软键盘中右下角的设置与监听
在项目中,多多少少会遇到修改软键盘右下角按钮的需求,虽然已经写过几次,但是还是觉得在这里专心做个笔记比较放心 ~ 我的那些软键盘Blog ~ Android进阶之路 - 常见软键盘操作行为 Andro ...
- Android进阶之路 - 批量下载、缓存图片
在日常项目开发中,关于图片批量下载,数据缓存的相关功能比比皆是,这次也是去年在项目中需要在本地缓存商品数据,所以用到了批量下载的功能,特此记录 ~ 关联篇 Android进阶之路 - 批量下载.缓存图 ...
- Android进阶之路 - 存、取、读 本地 Json 文件
最近在开发中又开始加载一些本地的json数据源,回头看之前竟然没记录,赶紧记录一波 ~ 如何准备一个合格的json文件? AndoridStudio中如何存放json文件? 如何读取本地Json文件数 ...
- 浅谈Android进阶之路
原址 过去十年是移动互联网蓬勃发展的黄金期,相信每个人也都享受到了移动互联网红利,在此期间,移动互联网经历了曙光期.成长期.成熟期.现在来说已经进入饱和期.依然记得在 2010-2013 年期间,从事 ...
- Android 进阶之路:ASM 修改字节码,这样学就对了!
本文已授权个人公众号「鸿洋」原创发布. 恢复双休了,准备捡起来写博客这件事,会尝试写好每一篇博客,准备写一个「进阶之路」的系列,希望对你有用. 没错,看了很多 ASM 入门的文章,都感觉文章写的很轻松 ...
- Android 进阶之路(我的博客文章目录)
原文地址:http://blog.csdn.net/u011240877 为了方便读者阅读以及自己回顾,总结写过的文章和一些想要写的文章目录如下: #1.Java Java 解惑:Comparable ...
- Android进阶之路 - 代码规范
后来 - 回头再看该篇的时候,发现当项目处于中后期的时候,命名规范还是不太严谨,扩展性有限,所以推荐各位可以借鉴阿里.美团.华为等大厂的命名规范 ~ 关于代码规范(主要针对Android),我于202 ...
最新文章
- 用.Net Reactor5打包加密dll文件和exe程序
- SAP MM MB1C + 523 移动类型的使用
- hadoop2.2.0 集群安装配置
- ewebeditor下利用ckplayer增加html5 (mp4)全平台的支持
- Exchange 2010和Exchange 2016共存部署-10:配置多域名证书
- 归并排序算法 C++实现与时间复杂度(考过)恋上数据结构笔记
- redux provider源码解析
- 每一次突破都是一种进步
- 《大道至简》阅读笔记
- MAC使用青花瓷(charles)抓包
- 解决Please define the NDK_PROJECT_PATH variable to point to it.
- 数据仓库模型设计与工具
- R语言中的apply(),lapply(),sapply(),tapply()函数以及示例
- [置顶] 一个程序员的科幻小说
- 网络存储NAS网络存储器术语解释
- 关于 Unicode 每个程序员应该知道的 5 件事
- linux常用命令-part3
- 交通信号灯课程设计_交通信号灯可以教设计师什么
- pip换源工具pqi
- ElasticSearch教程-索引的介绍
热门文章
- 卸载oracle10g服务端,oracle10g数据库服务器的安装与卸载.ppt
- 升级最新版本Android Studio Arctic Fox 遇到的问题
- 想报学大学生计算机学习班哪有,兴城学习计算机,兴城学计算机报班,兴城学计算机自学好还是报班好 - IT教育频道...
- 服务器安全狗 网站安全狗,全新升级!服务器安全狗和网站安全狗杞版重磅发布...
- 服务器安全狗占用cpu,服务器安全狗之悬浮窗口功能介绍
- 六级(2020/12-1) Text2
- 支付宝:web页面扫码支付、网站支付、支付宝即时到账 + springmvc
- 在线怎么将pdf文件转换成word文档转换器
- UC伯克利提出小批量MH测试:令MCMC方法在自编码器中更强劲
- ADSP-21569/ADSP-21593的开发入门(下)