RecyclerView的可滚动的列表实现,视图相邻的视图在屏幕上部分或完全可见(水平3个item,第一个和第三个显示一部分,第二个完全显示)
效果如图:


基于RecyclerView完成的(自定义控件)
public class DiscreteRecyclerView extends RecyclerView {

    public static final int NO_POSITION = DiscreteRecyclerLayoutManager.NO_POSITION;

    private static final int DEFAULT_ORIENTATION = DSVOrientation.HORIZONTAL.ordinal();

    private DiscreteRecyclerLayoutManager layoutManager;

    private List<ScrollStateChangeListener> scrollStateChangeListeners;
private List<OnItemChangedListener> onItemChangedListeners; private boolean isOverScrollEnabled; public DiscreteRecyclerView(Context context) {
super(context);
init(null);
} public DiscreteRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
} public DiscreteRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
} private void init(AttributeSet attrs) {
scrollStateChangeListeners = new ArrayList<>();
onItemChangedListeners = new ArrayList<>(); int orientation = DEFAULT_ORIENTATION;
if (attrs != null) {
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.DiscreteRecyclerView);
orientation = ta.getInt(R.styleable.DiscreteRecyclerView_dsv_orientation, DEFAULT_ORIENTATION);
ta.recycle();
} isOverScrollEnabled = getOverScrollMode() != OVER_SCROLL_NEVER; layoutManager = new DiscreteRecyclerLayoutManager(
getContext(), new ScrollStateListener(),
DSVOrientation.values()[orientation]);
setLayoutManager(layoutManager);
} @Override
public void setLayoutManager(LayoutManager layout) {
if (layout instanceof DiscreteRecyclerLayoutManager) {
super.setLayoutManager(layout);
} else {
throw new IllegalArgumentException(getContext().getString(R.string.dsv_ex_msg_dont_set_lm));
}
} @Override
public boolean fling(int velocityX, int velocityY) {
boolean isFling = super.fling(velocityX, velocityY);
if (isFling) {
layoutManager.onFling(velocityX, velocityY);
} else {
layoutManager.returnToCurrentPosition();
}
return isFling;
} @Nullable
public ViewHolder getViewHolder(int position) {
View view = layoutManager.findViewByPosition(position);
return view != null ? getChildViewHolder(view) : null;
} /**
* @return adapter position of the current item or -1 if nothing is selected
*/
public int getCurrentItem() {
return layoutManager.getCurrentPosition();
} public void setItemTransformer(DiscreteScrollItemTransformer transformer) {
layoutManager.setItemTransformer(transformer);
} public void setItemTransitionTimeMillis(@IntRange(from = 10) int millis) {
layoutManager.setTimeForItemSettle(millis);
} public void setSlideOnFling(boolean result){
layoutManager.setShouldSlideOnFling(result);
} public void setSlideOnFlingThreshold(int threshold){
layoutManager.setSlideOnFlingThreshold(threshold);
} public void setOrientation(DSVOrientation orientation) {
layoutManager.setOrientation(orientation);
} public void setOffscreenItems(int items) {
layoutManager.setOffscreenItems(items);
} public void setClampTransformProgressAfter(@IntRange(from = 1) int itemCount) {
if (itemCount <= 1) {
throw new IllegalArgumentException("must be >= 1");
}
layoutManager.setTransformClampItemCount(itemCount);
} public void setOverScrollEnabled(boolean overScrollEnabled) {
isOverScrollEnabled = overScrollEnabled;
setOverScrollMode(OVER_SCROLL_NEVER);
} public void addScrollStateChangeListener(@NonNull ScrollStateChangeListener<?> scrollStateChangeListener) {
scrollStateChangeListeners.add(scrollStateChangeListener);
} public void addScrollListener(@NonNull ScrollListener<?> scrollListener) {
addScrollStateChangeListener(new ScrollListenerAdapter(scrollListener));
} public void addOnItemChangedListener(@NonNull OnItemChangedListener<?> onItemChangedListener) {
onItemChangedListeners.add(onItemChangedListener);
} public void removeScrollStateChangeListener(@NonNull ScrollStateChangeListener<?> scrollStateChangeListener) {
scrollStateChangeListeners.remove(scrollStateChangeListener);
} public void removeScrollListener(@NonNull ScrollListener<?> scrollListener) {
removeScrollStateChangeListener(new ScrollListenerAdapter<>(scrollListener));
} public void removeItemChangedListener(@NonNull OnItemChangedListener<?> onItemChangedListener) {
onItemChangedListeners.remove(onItemChangedListener);
} private void notifyScrollStart(ViewHolder holder, int current) {
for (ScrollStateChangeListener listener : scrollStateChangeListeners) {
listener.onScrollStart(holder, current);
}
} private void notifyScrollEnd(ViewHolder holder, int current) {
for (ScrollStateChangeListener listener : scrollStateChangeListeners) {
listener.onScrollEnd(holder, current);
}
} private void notifyScroll(float position,
int currentIndex, int newIndex,
ViewHolder currentHolder, ViewHolder newHolder) {
for (ScrollStateChangeListener listener : scrollStateChangeListeners) {
listener.onScroll(position, currentIndex, newIndex,
currentHolder,
newHolder);
}
} private void notifyCurrentItemChanged(ViewHolder holder, int current) {
for (OnItemChangedListener listener : onItemChangedListeners) {
listener.onCurrentItemChanged(holder, current);
}
} private void notifyCurrentItemChanged() {
if (onItemChangedListeners.isEmpty()) {
return;
}
int current = layoutManager.getCurrentPosition();
ViewHolder currentHolder = getViewHolder(current);
notifyCurrentItemChanged(currentHolder, current);
} private class ScrollStateListener implements DiscreteRecyclerLayoutManager.ScrollStateListener { @Override
public void onIsBoundReachedFlagChange(boolean isBoundReached) {
if (isOverScrollEnabled) {
setOverScrollMode(isBoundReached ? OVER_SCROLL_ALWAYS : OVER_SCROLL_NEVER);
}
} @Override
public void onScrollStart() {
if (scrollStateChangeListeners.isEmpty()) {
return;
}
int current = layoutManager.getCurrentPosition();
ViewHolder holder = getViewHolder(current);
if (holder != null) {
notifyScrollStart(holder, current);
}
} @Override
public void onScrollEnd() {
if (onItemChangedListeners.isEmpty() && scrollStateChangeListeners.isEmpty()) {
return;
}
int current = layoutManager.getCurrentPosition();
ViewHolder holder = getViewHolder(current);
if (holder != null) {
notifyScrollEnd(holder, current);
notifyCurrentItemChanged(holder, current);
}
} @Override
public void onScroll(float currentViewPosition) {
if (scrollStateChangeListeners.isEmpty()) {
return;
}
int currentIndex = getCurrentItem();
int newIndex = layoutManager.getNextPosition();
if (currentIndex != newIndex) {
notifyScroll(currentViewPosition,
currentIndex, newIndex,
getViewHolder(currentIndex),
getViewHolder(newIndex));
}
} @Override
public void onCurrentViewFirstLayout() {
post(new Runnable() {
@Override
public void run() {
notifyCurrentItemChanged();
}
});
} @Override
public void onDataSetChangeChangedPosition() {
notifyCurrentItemChanged();
}
} public interface ScrollStateChangeListener<T extends ViewHolder> { void onScrollStart(@NonNull T currentItemHolder, int adapterPosition); void onScrollEnd(@NonNull T currentItemHolder, int adapterPosition); void onScroll(float scrollPosition,
int currentPosition,
int newPosition,
@Nullable T currentHolder,
@Nullable T newCurrent);
} public interface ScrollListener<T extends ViewHolder> { void onScroll(float scrollPosition,
int currentPosition, int newPosition,
@Nullable T currentHolder,
@Nullable T newCurrent);
} public interface OnItemChangedListener<T extends ViewHolder> {
/*
* This method will be also triggered when view appears on the screen for the first time.
* If data set is empty, viewHolder will be null and adapterPosition will be NO_POSITION
*/
void onCurrentItemChanged(@Nullable T viewHolder, int adapterPosition);
}
}
源码:https://github.com/DickyQie/android-discrete-recyclerview

 

android -------- RecyclerView的可(多个Item水平,垂直)滚动列表的实现的更多相关文章

  1. Android RecyclerView嵌套EditView实时更新Item数据

    一.场景(例如:购物车) 1.当我们需要以列表样式管理某些数据时,可能需要列表项的某个字段可编辑 2.编辑Item上的某个字段后可能还要更新相关字段的值 二.可能遇到的问题 1.列表滑动导致输入框中的 ...

  2. Android开发 ListView(垂直滚动列表项视图)的简单使用

    效果图: 使用方法: 1.在布局文件中加入ListView控件: <?xml version="1.0" encoding="utf-8"?> &l ...

  3. Android TextView多行垂直滚动

    在Android应用中,有时候需要TextView可以垂直滚动,今天我就介绍一下怎么实现的.在布局里: <TextView android:id="@+id/tvCWJ" a ...

  4. Android RecyclerView(瀑布流)水平/垂直方向分割线

     Android RecyclerView(瀑布流)水平/垂直方向分割线 Android RecyclerView不像过去的ListView那样随意的设置水平方向的分割线,如果要实现Recycle ...

  5. Android RecyclerView 实现支付宝首页效果

    Android RecyclerView 实现支付宝首页效果 [TOC] 虽然我本人不喜欢支付宝的,但是这个网格本身其实还是不错的,项目更新中更改了一个布局为网格模式,类似支付宝.(估计是产品抄袭的= ...

  6. Android RecyclerView的基本使用

    Android RecyclerView 在去年的Google I/O大会上就推出来了,以前经常使用的ListView 继承的是AbsListView,而RecyclerView则直接继承 ViewG ...

  7. Android RecyclerView体验(一)- 简介

    在网上关于RecyclerView的基本使用方式已经有了比较详细介绍,而且其设计结构也类似于ListView,所以本文将不重点介绍如何使用,在文末的引用中都可以相关内容.这里主要是介绍Recycler ...

  8. 浅谈Android RecyclerView

    Android RecyclerView 是Android5.0推出来的,导入support-v7包即可使用. 个人体验来说,RecyclerView绝对是一款功能强大的控件. 首先总结下Recycl ...

  9. (转载) Android RecyclerView 使用完全解析 体验艺术般的控件

    Android RecyclerView 使用完全解析 体验艺术般的控件 标签: Recyclerviewpager瀑布流 2015-04-16 09:07 721474人阅读 评论(458) 收藏  ...

  10. Android RecyclerView与ListView比较

    RecyclerView 概述 RecyclerView 集成自 ViewGroup .RecyclerView是Android-support-V7版本中新增的一个Widgets,官方对于它的介绍是 ...

随机推荐

  1. JavaScript 对象部署 Iterator 接口

    const name = { first:"hello", last:"world", fullname: "hello world" } ...

  2. MAC 终端走代理服务器

    问题描述: MAC 终端,默认不走代理服务器:即浏览器已经可以FQ,但是终端不行: 解决方案:直接设置终端的代理,本文 用的是 shadowSocksX: 打开终端,直接执行:(执行后,只对当前终端起 ...

  3. 使用 acme.sh 签发续签 Let‘s Encrypt 证书 泛域名证书

    1. 安装 acme.sh 安装很简单, 一个命令: curl https://get.acme.sh | sh 并创建 一个 bash 的 alias, 方便你的使用 alias acme.sh=~ ...

  4. 201901<<叶武滨时间管理100讲>>

    2019年1月份读物整理: 1月份,在喜马拉雅上听的这个课程叶武滨时间管理100讲,每天利用上下班时间听完的,对其中的一些讲的点很有感触.今年的读书计划,希望自己能把读的每本书都用思维导图的方式整理出 ...

  5. Dataguard配置总结

    Dataguard配置总结 本例情形 在主库存在运行的情况下,增加配置dataguard备库,实现双机热备,高可用性. 主库要求,归档模式,强制归档. 主库idty 备库idty_st 1.密码文件 ...

  6. Jmeter之Redis读写

    Jmeter之Redis读写 奔跑的小小鱼  关注  0.2 2019.03.21 18:25* 字数 1330 阅读 45评论 0喜欢 1 Jmeter插件访问Redis共有3种方式: 1)通过自已 ...

  7. clean exit - waiting for changes before restart

    在使用nodemon的时候,针对于同一个文件一次使用还好,当多次使用的时候就会出现这样的情况: 解决办法: nodemon clean exit 原因: 可能是因为缓存造成的:

  8. 原生js开发,无依赖、轻量级的现代浏览器图片懒加载插件,适合在移动端开发使用

    优势 1.原生js开发,不依赖任何框架或库 2.支持将各种宽高不一致的图片,自动剪切成默认图片的宽高 比如说你的默认图片是一张正方形的图片,则各种宽度高度不一样的图片,自动剪切成正方形. 完美解决移动 ...

  9. 复旦高等代数II(18级)每周一题

    本学期将继续进行高等代数每周一题的活动.计划从第一教学周开始,到第十五教学周结束,每周的周末公布一道思考题(预计15道),供大家思考和解答.每周一题将通过“高等代数官方博客”(以博文的形式)和“高等代 ...

  10. day16

    列表生成式语法[表达式 for in 遍历 if 条件]会从li一次去除所有值,进行判断 如果满足条件 就装到新的列表里 生成数据的函数函数体中又yield关键字yield 暂停函数的执行 还能返回一 ...