Android RecyclerView一個一個自動滾動,無限迴圈,聊天列表效果,跑馬燈效果
實現效果
看到這個效果,看到很多人用ViewFlipper實現,但是效果並不理想,於是我想到用RecyclerView試試。
主要是監聽recyclerView滑動,開始和暫停來控制,廢話不多說,上程式碼。
自定義RecyclerView
public class AutoPollRecyclerViewextends RecyclerView {
private static final long TIME_AUTO_POLL =16;
private static final long TIME_AUTO_POLL_1 =2000;
AutoPollTaskautoPollTask;
AutoPollTask1autoPollTask1;
private int index =0;
private boolean running; //標示是否正在自動輪詢
private boolean canRun;//標示是否可以自動輪詢,可在不需要的是否置false
private final int mTouchSlop;
public AutoPollRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
// autoPollTask = new AutoPollTask(this);
autoPollTask1 =new AutoPollTask1(this);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
/**
* 持續滑動(走馬燈)
*/
static class AutoPollTaskimplements Runnable {
private final WeakReferencemReference;
//使用弱引用持有外部類引用->防止記憶體洩漏
public AutoPollTask(AutoPollRecyclerView reference) {
this.mReference =new WeakReference(reference);
}
@Override
public void run() {
Log.e("AutoPollRecyclerView", System.currentTimeMillis() +"");
AutoPollRecyclerView recyclerView =mReference.get();
if (recyclerView !=null && recyclerView.running && recyclerView.canRun) {
recyclerView.scrollBy(2, 2);
recyclerView.postDelayed(recyclerView.autoPollTask, recyclerView.TIME_AUTO_POLL);
}
}
}
/***
* 一次只能滑一個item(輪播圖)
*/
static class AutoPollTask1implements Runnable {
private final WeakReferencemReference;
//使用弱引用持有外部類引用->防止記憶體洩漏
public AutoPollTask1(AutoPollRecyclerView reference) {
this.mReference =new WeakReference(reference);
}
@Override
public void run() {
AutoPollRecyclerView recyclerView =mReference.get();
if (recyclerView !=null && recyclerView.running && recyclerView.canRun) {
recyclerView.smoothScrollToPosition(++recyclerView.index);
recyclerView.postDelayed(recyclerView.autoPollTask1, TIME_AUTO_POLL_1);
}
}
}
//開啟:如果正在執行,先停止->再開啟
public void start() {
if (running)
stop();
canRun =true;
running =true;
// postDelayed(autoPollTask,TIME_AUTO_POLL);
postDelayed(autoPollTask1, TIME_AUTO_POLL_1);
}
public void stop() {
running =false;
// removeCallbacks(autoPollTask);
removeCallbacks(autoPollTask1);
}
//取消RecyclerView的慣性,使每次手動只能滑一個
int lastY =0;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
lastY = (int) ev.getRawY();
if (running)
stop();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_OUTSIDE:
int nowY = (int) ev.getRawY();
if (nowY -lastY >mTouchSlop) {//向下滑動
smoothScrollToPosition(index ==0 ?0 : --index);
if (canRun)
start();
return true;
}else if (lastY - nowY >mTouchSlop) {//向上滑動
smoothScrollToPosition(++index);
if (canRun)
start();
return true;
}
break;
}
return super.dispatchTouchEvent(ev);
}
// 實現漸變效果
PaintmPaint;
private int layerId;
private LinearGradientlinearGradient;
private int preWidth =0;// Recyclerview寬度動態變化時,監聽每一次的寬度
public void doTopGradualEffect(final int itemViewWidth) {
mPaint =new Paint();
// dst_in 模式,實現底層透明度隨上層透明度進行同步顯示(即上層為透明時,下層就透明,並不是上層覆蓋下層)
final Xfermode xfermode =new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
mPaint.setXfermode(xfermode);
addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
public void onDrawOver(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(canvas, parent, state);
// 當linearGradient為空即第一次繪製 或 Recyclerview寬度發生改變時,重新計算透明位置
if (linearGradient ==null ||preWidth != parent.getWidth()) {
// 透明位置從最後一個 itemView 的一半處到 Recyclerview 的最右邊
linearGradient =new LinearGradient(parent.getWidth() - (itemViewWidth /2), 0.0f, parent.getWidth(), 0.0f, new int[]{Color.BLACK, 0}, null, Shader.TileMode.CLAMP);
preWidth = parent.getWidth();
}
mPaint.setXfermode(xfermode);
mPaint.setShader(linearGradient);
canvas.drawRect(0.0f, 0.0f, parent.getRight(), parent.getBottom(), mPaint);
mPaint.setXfermode(null);
canvas.restoreToCount(layerId);
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
// 此處 Paint的引數這裡傳的null, 在傳入 mPaint 時會出現第一次開啟黑屏閃現的問題
// 注意 saveLayer 不能省也不能移動到onDrawOver方法裡
layerId = c.saveLayer(0.0f, 0.0f, (float) parent.getWidth(), (float) parent.getHeight(), null, Canvas.ALL_SAVE_FLAG);
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
// 該方法作用自行百度
super.getItemOffsets(outRect, view, parent, state);
}
});
}
}
自定義Manger控制滑動速度
/**
* 控制滑動速度的LinearLayoutManager
*/
public class ScrollSpeedLinearLayoutMangerextends
LinearLayoutManager {
private float MILLISECONDS_PER_INCH =0.03f;
private Contextcontxt;
public ScrollSpeedLinearLayoutManger(Context context) {
super(context);
this.contxt = context;
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
LinearSmoothScroller linearSmoothScroller =
new LinearSmoothScroller(recyclerView.getContext()) {
@Override
public PointFcomputeScrollVectorForPosition(int targetPosition) {
return ScrollSpeedLinearLayoutManger.this
.computeScrollVectorForPosition(targetPosition);
}
//This returns the milliseconds it takes to
//scroll one pixel.
@Override
protected float calculateSpeedPerPixel
(DisplayMetrics displayMetrics) {
setSpeedSlow();
return MILLISECONDS_PER_INCH / displayMetrics.density;
// return 700;
//返回滑動一個pixel需要多少毫秒
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
public void setSpeedSlow() {
//自己在這裡用density去乘,希望不同解析度裝置上滑動速度相同
//0.3f是自己估摸的一個值,可以根據不同需求自己修改
MILLISECONDS_PER_INCH =contxt.getResources().getDisplayMetrics().density *3f;
}
public void setSpeedFast() {
MILLISECONDS_PER_INCH =contxt.getResources().getDisplayMetrics().density *0.03f;
}
}
自定義Adapter
public class AutoPollAdapterextends RecyclerView.Adapter {
/**
* 事件回撥監聽
*/
private OnItemClickListeneronItemClickListener;
private Contextcontext;
private ListlistBeans;
public AutoPollAdapter(Context context, List listBeans) {
this.context = context;
this.listBeans = listBeans;
}
@Override
public ViewHolderonCreateViewHolder(ViewGroup parent, int viewType) {
// 例項化展示的view
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_auto_poll, parent, false);
// 例項化viewholder
ViewHolder viewHolder =new ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
holder.tvName.setText(listBeans.get(position %listBeans.size()));
holder.tvComment.setText("使用者評論" + position);
}
@Override
public int getItemCount() {
//主要在這,實現無線輪播效果
return Integer.MAX_VALUE;
}
public static class ViewHolderextends RecyclerView.ViewHolder {
@BindView(R.id.simple_header)
SimpleDraweeViewsimpleCover;
@BindView(R.id.tv_name)
TextViewtvName;
@BindView(R.id.tv_comment)
TextViewtvComment;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
/**
* 設定回撥監聽
*
* @param listener
*/
public void setOnItemClickListener(OnItemClickListener listener) {
this.onItemClickListener = listener;
}
public interface OnItemClickListener {
void onItemClick(int position);
}
}
佈局是很簡單的就不貼了
使用方法
在Acitivity中使用
ScrollSpeedLinearLayoutManger layoutManager =new ScrollSpeedLinearLayoutManger(this);
layoutManager.setSmoothScrollbarEnabled(true);
layoutManager.setAutoMeasureEnabled(true);
recyclerView.setLayoutManager(layoutManager);// 佈局管理器。
recyclerView.setHasFixedSize(true);// 如果Item夠簡單,高度是確定的,開啟FixSize將提高效能。
recyclerView.setItemAnimator(new DefaultItemAnimator());// 設定Item預設動畫,加也行,不加也行。
recyclerView.setAdapter(new AutoPollAdapter(TestActivity.this, list));
recyclerView.start();
recyclerView.doTopGradualEffect(StringUtil.ScreenWidth(this));
好了,到此結束,點個贊再走唄...
歡迎大家進群探討Android相關技術 群號:548154942