Recycleview實(shí)現(xiàn)無(wú)限自動(dòng)輪播
概述
RecycleView實(shí)現(xiàn)特定數(shù)據(jù)無(wú)限重復(fù)滑動(dòng)在我看來(lái)不外乎有兩種方法
1.修改adpter的復(fù)用機(jī)制,無(wú)限復(fù)用數(shù)據(jù)
2.在adpter中返回?cái)?shù)據(jù)長(zhǎng)度返回Integer的最大值
由于第一種雖然能實(shí)現(xiàn)數(shù)據(jù)的無(wú)限重復(fù)但是數(shù)據(jù)位還是沒(méi)有任何變化,所以在自動(dòng)跳轉(zhuǎn)至最后的時(shí)候無(wú)法在向下一位輪播,所以在這里我使用第二種方式實(shí)現(xiàn)自動(dòng)輪播
簡(jiǎn)單講述修改adpter的復(fù)用機(jī)制
我們拿LinearLayoutManager線(xiàn)性的為例子,我們只需要重新LinearLayoutManager在繪制的時(shí)候做一些手手腳就可以實(shí)現(xiàn)
package com.li.liproject.recycle;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.LinearSmoothScroller;
import androidx.recyclerview.widget.RecyclerView;
/**
* @author 版本:1.0
* 創(chuàng)建日期:2020/4/14 14
* 描述:
*/
public class ScrollSpeedLinearLayoutManger extends LinearLayoutManager {
public ScrollSpeedLinearLayoutManger(Context context) {
super(context);
}
public ScrollSpeedLinearLayoutManger(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public ScrollSpeedLinearLayoutManger(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
}
// 1 在RecyclerView初始化時(shí),會(huì)被調(diào)用兩次。
// 2 在調(diào)用adapter.notifyDataSetChanged()時(shí),會(huì)被調(diào)用。
// 3 在調(diào)用setAdapter替換Adapter時(shí),會(huì)被調(diào)用。
// 4 在RecyclerView執(zhí)行動(dòng)畫(huà)時(shí),它也會(huì)被調(diào)用。
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
Log.d("TAG","onLayoutChildren ");
if (getItemCount() == 0){
detachAndScrapAttachedViews(recycler);
return;
}
//state.isPreLayout()是支持動(dòng)畫(huà)的
if (getItemCount() == 0 && state.isPreLayout()){
return;
}
//將當(dāng)前Recycler中的view全部移除并放到報(bào)廢緩存里,之后優(yōu)先重用緩存里的view
detachAndScrapAttachedViews(recycler);
int actualHeight = 0;
for (int i = 0 ;i < getItemCount() ; i++){
View scrap = recycler.getViewForPosition(i);
addView(scrap);
measureChildWithMargins(scrap,0,0);
int width = getDecoratedMeasuredWidth(scrap);
int height = getDecoratedMeasuredHeight(scrap);
layoutDecorated(scrap,0,actualHeight,width,actualHeight+height);
actualHeight+=height;
//超出界面的就不畫(huà)了,也不add了
if (actualHeight > getHeight()){
break;
}
}
}
@Override
public boolean canScrollVertically() {
return true;
}
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
Log.d("feifeifei","getChildCount() " + getChildCount() + " recycler.getScrapList().size() " + recycler.getScrapList().size());
//界面向下滾動(dòng)的時(shí)候,dy為正,向上滾動(dòng)的時(shí)候dy為負(fù)
//填充
fill(dy,recycler,state);
//滾動(dòng)
offsetChildrenVertical(dy*-1);
//回收已經(jīng)離開(kāi)界面的
recycleOut(dy,recycler,state);
return dy;
}
private void fill(int dy, RecyclerView.Recycler recycler, RecyclerView.State state){
//向下滾動(dòng)
if (dy > 0){
//先在底部填充
View lastView = getChildAt(getChildCount() -1);
int lastPos = getPosition(lastView);
if (lastView.getBottom() - dy < getHeight()){
View scrap;
if (lastPos == getItemCount() -1){
scrap = recycler.getViewForPosition(0);
}else {
scrap = recycler.getViewForPosition(lastPos+1);
}
addView(scrap);
measureChildWithMargins(scrap,0,0);
int width = getDecoratedMeasuredWidth(scrap);
int height = getDecoratedMeasuredHeight(scrap);
layoutDecorated(scrap,0,lastView.getBottom(),width,lastView.getBottom()+height);
}
}else {
//向上滾動(dòng)
//現(xiàn)在頂部填充
View firstView = getChildAt(0);
int layoutPostion = getPosition(firstView);
if (firstView.getTop() >= 0 ){
View scrap ;
if (layoutPostion == 0){
scrap = recycler.getViewForPosition(getItemCount()-1);
}else {
scrap = recycler.getViewForPosition(layoutPostion -1);
}
addView(scrap,0);
measureChildWithMargins(scrap,0,0);
int width = getDecoratedMeasuredWidth(scrap);
int height = getDecoratedMeasuredHeight(scrap);
layoutDecorated(scrap,0,firstView.getTop() - height,width,firstView.getTop());
}
}
}
private void recycleOut(int dy, RecyclerView.Recycler recycler, RecyclerView.State state){
for (int i = 0 ; i <getChildCount() ;i++){
View view = getChildAt(i);
if (dy >0){
if (view.getBottom()-dy <0){
Log.d("feifeifei","recycleOut " + i);
removeAndRecycleView(view,recycler);
}
}else {
if (view.getTop()-dy > getHeight()){
Log.d("feifeifei","recycleOut " + i);
removeAndRecycleView(view,recycler);
}
}
}
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
private class CenterSmoothScroller extends LinearSmoothScroller {
public CenterSmoothScroller(Context context) {
super(context);
}
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return 0.2f;
}
}
}
大概就是這么寫(xiě)的網(wǎng)格的需要自己重新寫(xiě)因?yàn)橛?jì)算會(huì)有區(qū)別,這里簡(jiǎn)單的講述一下
正題
Adpter適配器的實(shí)現(xiàn)
寫(xiě)法沒(méi)什么區(qū)別唯一的getItemCount 和onBindViewHolder要做一下處理大概如下
public class AdAuditorAdapter extends RecyclerView.Adapter<AdAuditorAdapter.MyViewHolder> {
private Context mContext;
private List<String> mData;
public AdAuditorAdapter(Context mContext, List<String> mData) {
this.mContext = mContext;
this.mData = mData;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
MyViewHolder holder = new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_adauditor, viewGroup, false));
return holder;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, @SuppressLint("RecyclerView") int i) {
Log.e("HHHHHHHHH", "onBindViewHolder: -->"+i );
//取余否則會(huì)出現(xiàn)索引越界
myViewHolder.tv_1.setText(mData.get(i%mData.size()));
myViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onClick(v, i%mData.size(), 3);
}
});
}
@Override
public int getItemCount() {
//返回adpter最大值
return Integer.MAX_VALUE;
}
public void update(List<String> list) {
this.mData = list;
notifyDataSetChanged();
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv_1;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
tv_1 = itemView.findViewById(R.id.tv_1); //ID
}
}
public MyClickListener getListener() {
return listener;
}
public void setMyClickListener(MyClickListener listener) {
this.listener = listener;
}
MyClickListener listener;
public interface MyClickListener {
void onClick(View view, int position, int type);
}
public List<String> getData() {
return mData;
}
}
activity的實(shí)現(xiàn)
1基本實(shí)現(xiàn)
1.1 添加假數(shù)據(jù)寫(xiě)好點(diǎn)擊事件
1.2 用handler延遲發(fā)消息 mRecyclerView.smoothScrollToPosition(position);移動(dòng)到指定位置
1.3 點(diǎn)擊停止移動(dòng)
2效果優(yōu)化
2.1 添加勻速阻尼效果
2.2 實(shí)現(xiàn)無(wú)限輪播考慮數(shù)值超過(guò)Integer最大值情況
2.3 點(diǎn)擊正在輪播時(shí)的recycleview會(huì)停止輪播,再次點(diǎn)擊才會(huì)執(zhí)行點(diǎn)擊事件(優(yōu)化為點(diǎn)擊停止并執(zhí)行點(diǎn)擊事件)
阻尼效果就是減少滑動(dòng)速率
我們這么做
package com.li.liproject.recycle;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearSmoothScroller;
import androidx.recyclerview.widget.RecyclerView;
/**
* @author 版本:1.0
* 創(chuàng)建日期:2020/4/14 14
* 描述:
*/
public class ScrollSpeedGridLayoutManager1 extends GridLayoutManager {
public ScrollSpeedGridLayoutManager1(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public ScrollSpeedGridLayoutManager1(Context context, int spanCount) {
super(context, spanCount);
}
public ScrollSpeedGridLayoutManager1(Context context, int spanCount, int orientation, boolean reverseLayout) {
super(context, spanCount, orientation, reverseLayout);
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
private class CenterSmoothScroller extends LinearSmoothScroller {
public CenterSmoothScroller(Context context) {
super(context);
}
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return 10f;//滑動(dòng)速率問(wèn)題
}
}
}
activity全部代碼
package com.li.liproject.recycle;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.li.liproject.MainActivity;
import com.li.liproject.R;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
/**
* @author 版本:1.0
* 創(chuàng)建日期:2020/4/14 14
* 描述:
*/
public class RecycleViewActivity extends AppCompatActivity {
static RecyclerView rv_1;
private static int HANDLER_MSG = 0x0011;
private static int HANDLER_LONG_MSG = 0x0021;
static int position = 0;
static int addNum = 3;
@SuppressLint("HandlerLeak")
private static Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
if (msg.what == HANDLER_MSG) {
// 9宮格效果實(shí)現(xiàn)速率相同
if (addNum==3){
position = position + addNum;
addNum = 6;
}else {
position = position + addNum;
addNum = 3;
}
Log.e("TAG", "handleMessage: -->" + position);
smoothMoveToPosition(rv_1, position >= 0 ? position : 0);
if (position==Integer.MAX_VALUE/2){
//點(diǎn)擊或超過(guò)2分之Integer.MAX_VALU重置adpter
LongAutoMove();
}else {
AutoMove();
}
}else if (msg.what==HANDLER_LONG_MSG){
position = 0;
addNum = 3;
Log.e("TAG", "handleMessage: -->" + position);
smoothMoveToPosition(rv_1, 0);
AutoMove();
}
}
};
private static AdAuditorAdapter adAuditorAdapter;
static List<String> strings;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycle);
rv_1 = findViewById(R.id.rv_1);
strings = new ArrayList<>();
for (int i = 0; i < 50; i++) {
strings.add(i + "");
}
adAuditorAdapter = new AdAuditorAdapter(this, strings);
adAuditorAdapter.setMyClickListener(new AdAuditorAdapter.MyClickListener() {
@Override
public void onClick(View view, int position, int type) {
Toast.makeText(RecycleViewActivity.this, adAuditorAdapter.getData().get(position), Toast.LENGTH_SHORT).show();
StopMove();
}
});
GridLayoutManager layoutManager = new ScrollSpeedGridLayoutManager1(this,3,GridLayoutManager.HORIZONTAL, false);
rv_1.setLayoutManager(layoutManager);
rv_1.setAdapter(adAuditorAdapter);
rv_1.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
// if (mShouldScroll && RecyclerView.SCROLL_STATE_IDLE == newState) {
// mShouldScroll = false;
// smoothMoveToPosition(recyclerView, mToPosition);
// }
Log.e("TAG", "onScrollStateChanged11111111: -->" + newState);
if (newState == 1) {
// RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(recyclerView.getRootView());
recyclerView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(RecycleViewActivity.this, adAuditorAdapter.getData().get(position)+"........", Toast.LENGTH_SHORT).show();
}
});
StopMove();
LongAutoMove();
}
}
// @Override
// public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
// super.onScrolled(recyclerView, dx, dy);
// Log.e("TAG", "onScrolled: dx=" +dx +" dy="+dy );
// }
});
rv_1.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction()==MotionEvent.ACTION_DOWN){
//監(jiān)測(cè)點(diǎn)擊位置找到view實(shí)現(xiàn)點(diǎn)擊事件
View childView = rv_1.findChildViewUnder(event.getX(), event.getY());
Log.e("GGGGGGGGGGGGGGGGG", "onTouch: -->"+rv_1.getChildLayoutPosition(childView));
adAuditorAdapter.getListener().onClick(v, rv_1.getChildLayoutPosition(childView),1);
}
return false;
}
});
AutoMove();
}
private static void AutoMove() {
handler.removeMessages(HANDLER_MSG);
handler.sendEmptyMessageDelayed(HANDLER_MSG, 2000);
}
private static void LongAutoMove() {
if (handler.hasMessages(HANDLER_MSG)) {
handler.removeMessages(HANDLER_LONG_MSG);
}
handler.sendEmptyMessageDelayed(HANDLER_LONG_MSG, 5000);
}
public static void StopMove() {
if (handler.hasMessages(HANDLER_MSG)) {
handler.removeMessages(HANDLER_MSG);
}
}
//目標(biāo)項(xiàng)是否在最后一個(gè)可見(jiàn)項(xiàng)之后
private static boolean mShouldScroll;
//記錄目標(biāo)項(xiàng)位置
private static int mToPosition;
/**
* 滑動(dòng)到指定位置
*/
private static void smoothMoveToPosition(RecyclerView mRecyclerView, final int position) {
if (position==0){
mRecyclerView.setAdapter(adAuditorAdapter);
}
mRecyclerView.smoothScrollToPosition(position);
mToPosition = position;
mShouldScroll = true;
}
@Override
protected void onDestroy() {
super.onDestroy();
if (handler!=null){
handler.removeCallbacksAndMessages(null);
handler= null;
}
if (adAuditorAdapter!=null) {
adAuditorAdapter= null;
}
}
}
自動(dòng)輪播效果基本實(shí)現(xiàn)
這里的Demo只寫(xiě)了大概的效果還有很多的東西需要優(yōu)化一下,才能拿到項(xiàng)目中使用
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 在RecyclerView中實(shí)現(xiàn)button的跳轉(zhuǎn)功能
- Android recycleView的應(yīng)用和點(diǎn)擊事件實(shí)例詳解
- Android 中RecycleView實(shí)現(xiàn)item的點(diǎn)擊事件
- Android實(shí)現(xiàn)Recycleview懸浮粘性頭部外加右側(cè)字母導(dǎo)航
- 去掉RecycleView或者ListView上下滑動(dòng)陰影的方法
- Android移動(dòng)開(kāi)發(fā)recycleView的頁(yè)面點(diǎn)擊跳轉(zhuǎn)設(shè)計(jì)實(shí)現(xiàn)
相關(guān)文章
詳解Android中的沉浸式狀態(tài)欄效果實(shí)例
本篇文章主要介紹了Android中的沉浸式狀態(tài)欄效果,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12
Android Compose衰減動(dòng)畫(huà)Animatable使用詳解
這篇文章主要為大家介紹了Android Compose衰減動(dòng)畫(huà)Animatable使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
詳解如何在Android studio中更新sdk版本和build-tools版本
這篇文章主要介紹了如何在Android studio中更新sdk版本和build-tools版本,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Android定時(shí)器Timer的停止和重啟實(shí)現(xiàn)代碼
本篇文章主要介紹了Android實(shí)現(xiàn)定時(shí)器Timer的停止和重啟實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
Android開(kāi)發(fā)中Google為什么不讓用Handler的runWithScissors()
這篇文章主要介紹了Android開(kāi)發(fā)中Google為什么不讓用Handler的runWithScissors(),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09
Android?TextView冷門(mén)實(shí)用方法技巧
這篇文章主要為大家介紹了Android?TextView冷門(mén)實(shí)用方法技巧示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
android開(kāi)機(jī)自啟動(dòng)app示例分享
這篇文章主要介紹了android開(kāi)機(jī)自動(dòng)啟動(dòng)APP的方法,大家參考使用吧2014-01-01
Android自定義水波紋動(dòng)畫(huà)Layout實(shí)例代碼
這篇文章主要介紹了Android自定義水波紋動(dòng)畫(huà)Layout的實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11
Android 自定義縮短Toast顯示時(shí)間的實(shí)例代碼
這篇文章主要介紹了Android 自定義縮短Toast顯示時(shí)間,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01
Android編程設(shè)計(jì)模式之抽象工廠模式詳解
這篇文章主要介紹了Android編程設(shè)計(jì)模式之抽象工廠模式,結(jié)合實(shí)例形式詳細(xì)分析了Android抽象工廠模式的概念、原理、使用方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-12-12

