博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 自己定义RecyclerView 实现真正的Gallery效果
阅读量:5013 次
发布时间:2019-06-12

本文共 12271 字,大约阅读时间需要 40 分钟。

转载请标明出处: 。本文出自:

上一篇博客我使用自己定义HorizontalScrollView写了一个具有HorizontalScrollView效果和ViewPager特性的横向图片轮播。详见:。事实上制作横向滚动的不得不说另一个控件,就是Google官方近期新添加的RecyclerView,据说是ListView的升级版本号,本篇博客,首先介绍RecyclerView的使用方法。然后经行一定的分析。最后自己定义一下RecyclerView实现我们须要的相冊效果。

1、RecyclerView的基本使用方法

首先主Activity的布局文件:

Item的布局文件:

数据适配器:

package com.example.zhy_horizontalscrollview03;import java.util.List;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 android.widget.TextView;public class GalleryAdapter extends		RecyclerView.Adapter
{ private LayoutInflater mInflater; private List
mDatas; public GalleryAdapter(Context context, List
datats) { mInflater = LayoutInflater.from(context); mDatas = datats; } public static class ViewHolder extends RecyclerView.ViewHolder { public ViewHolder(View arg0) { super(arg0); } ImageView mImg; TextView mTxt; } @Override public int getItemCount() { return mDatas.size(); } /** * 创建ViewHolder */ @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { View view = mInflater.inflate(R.layout.activity_index_gallery_item, viewGroup, false); ViewHolder viewHolder = new ViewHolder(view); viewHolder.mImg = (ImageView) view .findViewById(R.id.id_index_gallery_item_image); return viewHolder; } /** * 设置值 */ @Override public void onBindViewHolder(final ViewHolder viewHolder, final int i) { viewHolder.mImg.setImageResource(mDatas.get(i)); }}
能够看到数据适配器与BaseAdapter比較发生了相当大的变化,主要有3个方法:

getItemCount 这个不用说,获取总的条目数

onCreateViewHolder 创建ViewHolder

onBindViewHolder 将数据绑定至ViewHolder

可见,RecyclerView对ViewHolder也进行了一定的封装。可是假设你细致观察。你会发出一个疑问,ListView里面有个getView返回View为Item的布局。那么这个Item的样子在哪控制?

事实上是这种,我们创建的ViewHolder必须继承RecyclerView.ViewHolder,这个RecyclerView.ViewHolder的构造时必须传入一个View,这个View相当于我们ListView getView中的convertView (即:我们须要inflate的item布局须要传入)。

另一点。ListView中convertView是复用的,在RecyclerView中,是把ViewHolder作为缓存的单位了。然后convertView作为ViewHolder的成员变量保持在ViewHolder中。也就是说,假设没有屏幕显示10个条目,则会创建10个ViewHolder缓存起来,每次复用的是ViewHolder,所以他把getView这种方法变为了onCreateViewHolder。有兴趣的自己打印下Log,測试下。

最后在Activity中使用:

package com.example.zhy_horizontalscrollview03;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import android.app.Activity;import android.os.Bundle;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.Window;public class MainActivity extends Activity{	private RecyclerView mRecyclerView;	private GalleryAdapter mAdapter;	private List
mDatas; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); initDatas(); //得到控件 mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview_horizontal); //设置布局管理器 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); mRecyclerView.setLayoutManager(linearLayoutManager); //设置适配器 mAdapter = new GalleryAdapter(this, mDatas); mRecyclerView.setAdapter(mAdapter); } private void initDatas() { mDatas = new ArrayList
(Arrays.asList(R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d, R.drawable.e, R.drawable.f, R.drawable.g, R.drawable.h, R.drawable.l)); }}
使用起来也非常方便,唯一的差别就是要设置LayoutManager,眼下仅仅有一个实现类。就是LinearLayoutManager。能够设置为水平或者垂直。

最后效果图:

效果非常不错,这就是RecyclerView的基本使用方法了。可是你会发现一个坑爹的地方,居然没有提供setOnItemClickListener这个回调。要不要这么坑爹。。。

2、为RecyclerView加入OnItemClickListener回调

尽管它没有提供,可是加入个OnItemClickListener对我们来说还不是小菜一碟~

我决定在Adapter中加入这个回调接口:

package com.example.zhy_horizontalscrollview03;import java.util.List;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup;import android.widget.ImageView;import android.widget.TextView;public class GalleryAdapter extends		RecyclerView.Adapter
{ /** * ItemClick的回调接口 * @author zhy * */ public interface OnItemClickLitener { void onItemClick(View view, int position); } private OnItemClickLitener mOnItemClickLitener; public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener) { this.mOnItemClickLitener = mOnItemClickLitener; } private LayoutInflater mInflater; private List
mDatas; public GalleryAdapter(Context context, List
datats) { mInflater = LayoutInflater.from(context); mDatas = datats; } public static class ViewHolder extends RecyclerView.ViewHolder { public ViewHolder(View arg0) { super(arg0); } ImageView mImg; TextView mTxt; } @Override public int getItemCount() { return mDatas.size(); } @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { View view = mInflater.inflate(R.layout.activity_index_gallery_item, viewGroup, false); ViewHolder viewHolder = new ViewHolder(view); viewHolder.mImg = (ImageView) view .findViewById(R.id.id_index_gallery_item_image); return viewHolder; } @Override public void onBindViewHolder(final ViewHolder viewHolder, final int i) { viewHolder.mImg.setImageResource(mDatas.get(i)); //假设设置了回调,则设置点击事件 if (mOnItemClickLitener != null) { viewHolder.itemView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mOnItemClickLitener.onItemClick(viewHolder.itemView, i); } }); } }}
非常easy,创建一个接口,提供一个设置入口。然后在onBindViewHolder中推断即可。

最后在主Activity中设置监听:

mAdapter = new GalleryAdapter(this, mDatas);		mAdapter.setOnItemClickLitener(new OnItemClickLitener()		{			@Override			public void onItemClick(View view, int position)			{				Toast.makeText(MainActivity.this, position+"", Toast.LENGTH_SHORT)						.show();			}		});		mRecyclerView.setAdapter(mAdapter);
好了,这样即可了,看效果图:

效果还是不错的。接下来我想改成相冊效果,即上面显示一张大图,以下的RecyclerView做为图片切换的指示器。

3、自己定义RecyclerView实现滚动时内容联动

首先改动下布局:

布局文件:

加入一个显示大图的区域。把RecyclerView改为自己定义的。

然后看我们自己定义RecyclerView的代码:

package com.example.zhy_horizontalscrollview03;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;public class CopyOfMyRecyclerView extends RecyclerView{	public CopyOfMyRecyclerView(Context context, AttributeSet attrs)	{		super(context, attrs);	}	private View mCurrentView;	/**	 * 滚动时回调的接口	 */	private OnItemScrollChangeListener mItemScrollChangeListener;	public void setOnItemScrollChangeListener(			OnItemScrollChangeListener mItemScrollChangeListener)	{		this.mItemScrollChangeListener = mItemScrollChangeListener;	}	public interface OnItemScrollChangeListener	{		void onChange(View view, int position);	}	@Override	protected void onLayout(boolean changed, int l, int t, int r, int b)	{		super.onLayout(changed, l, t, r, b);		mCurrentView = getChildAt(0);		if (mItemScrollChangeListener != null)		{			mItemScrollChangeListener.onChange(mCurrentView,					getChildPosition(mCurrentView));		}	}	@Override	public boolean onTouchEvent(MotionEvent e)	{		if (e.getAction() == MotionEvent.ACTION_MOVE)		{			mCurrentView = getChildAt(0);			// Log.e("TAG", getChildPosition(getChildAt(0)) + "");			if (mItemScrollChangeListener != null)			{				mItemScrollChangeListener.onChange(mCurrentView,						getChildPosition(mCurrentView));			}		}		return super.onTouchEvent(e);	}}
定义了一个滚动时回调的接口,然后在onTouchEvent中,监听ACTION_MOVE。用户手指滑动时,不断把当前第一个View回调回去~

关于我咋知道getChildAt(0)和getChildPosition()可用,起初我以为有getFirstVisibleItem这种方法,后来发现么有;可是发现了getRecycledViewPool()看名字我认为是Viewholder那个缓存队列。我想那么直接取这个队列的第一个不就是我要的View么。后来没有成功。我就观察它内部的View,最后发现,第一个显示的始终是它第一个child。至于getChildPosition这个看方法就看出来了。

如今的效果:

和我之前那个样例的效果是一模一样的,只是,我还想做一些改变,我认为Gallery或者说相冊的指示器,以下可能1000来张图片。我不仅喜欢手指在屏幕上滑动时,图片会自己主动切换。我还希望,假设我给指示器一个加速度,即使手指离开,以下还在滑动,上面也会联动 。并且我还想做些优化,直接在ACTION_MOVE中回调。触发的频率太高了,理论上一张图片仅仅会触发一次~~

4、优化与打造真正的Gallery效果

既然希望手指离开还能联动,那么不仅须要ACTION_MOVE须要监听,还得监听一个加速度,速度到达一定值。然后继续移动~~再理一理。须要这么麻烦么。不是能滚动么,那么应该有OnScrollListener啊,小看一把,果然有。哈哈哈~天助我也,以下看改动后的代码:

package com.example.zhy_horizontalscrollview03;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.RecyclerView.OnScrollListener;import android.util.AttributeSet;import android.view.View;public class MyRecyclerView extends RecyclerView implements OnScrollListener{	/**	 * 记录当前第一个View	 */	private View mCurrentView;	private OnItemScrollChangeListener mItemScrollChangeListener;	public void setOnItemScrollChangeListener(			OnItemScrollChangeListener mItemScrollChangeListener)	{		this.mItemScrollChangeListener = mItemScrollChangeListener;	}	public interface OnItemScrollChangeListener	{		void onChange(View view, int position);	}	public MyRecyclerView(Context context, AttributeSet attrs)	{		super(context, attrs);		// TODO Auto-generated constructor stub		this.setOnScrollListener(this);	}	@Override	protected void onLayout(boolean changed, int l, int t, int r, int b)	{		super.onLayout(changed, l, t, r, b);		mCurrentView = getChildAt(0);		if (mItemScrollChangeListener != null)		{			mItemScrollChangeListener.onChange(mCurrentView,					getChildPosition(mCurrentView));		}	}	@Override	public void onScrollStateChanged(int arg0)	{	}	/**	 * 	 * 滚动时,推断当前第一个View是否发生变化,发生才回调	 */	@Override	public void onScrolled(int arg0, int arg1)	{		View newView = getChildAt(0);		if (mItemScrollChangeListener != null)		{			if (newView != null && newView != mCurrentView)			{				mCurrentView = newView ;				mItemScrollChangeListener.onChange(mCurrentView,						getChildPosition(mCurrentView));			}		}	}}
我放弃了重写onTouchEvent方法。而是让这个类实现RecyclerView.OnScrollListener接口,然后设置监听,在onScrolled里面进行推断。

至于优化:我使用了一个成员变化存储当前第一个View,仅仅有第一个View发生变化时才回调~~太完美了~

看MainActivity:

package com.example.zhy_horizontalscrollview03;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import android.app.Activity;import android.os.Bundle;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;import android.view.Window;import android.widget.ImageView;import android.widget.Toast;import com.example.zhy_horizontalscrollview03.GalleryAdapter.OnItemClickLitener;import com.example.zhy_horizontalscrollview03.MyRecyclerView.OnItemScrollChangeListener;public class MainActivity extends Activity{	private MyRecyclerView mRecyclerView;	private GalleryAdapter mAdapter;	private List
mDatas; private ImageView mImg ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); mImg = (ImageView) findViewById(R.id.id_content); mDatas = new ArrayList
(Arrays.asList(R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d, R.drawable.e, R.drawable.f, R.drawable.g, R.drawable.h, R.drawable.l)); mRecyclerView = (MyRecyclerView) findViewById(R.id.id_recyclerview_horizontal); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); mRecyclerView.setLayoutManager(linearLayoutManager); mAdapter = new GalleryAdapter(this, mDatas); mRecyclerView.setAdapter(mAdapter); mRecyclerView.setOnItemScrollChangeListener(new OnItemScrollChangeListener() { @Override public void onChange(View view, int position) { mImg.setImageResource(mDatas.get(position)); }; }); mAdapter.setOnItemClickLitener(new OnItemClickLitener() { @Override public void onItemClick(View view, int position) {// Toast.makeText(getApplicationContext(), position + "", Toast.LENGTH_SHORT)// .show(); mImg.setImageResource(mDatas.get(position)); } }); }}
代码没什么变化~多了个设置回调~

效果图:

能够看到不仅支持手机在上面移动时的变化,假设我给了一个加速度,以下持续滚动。上面也会持续变化~~大赞~每张图片回调一次,效率也相当不错。

好了。看完这边博客,相信大家对于RecyclerView有了一定的认识,甚至对于怎样改造一个控件也多了一份了解~~

假设认为不错。就留个言或者点个赞,表示对我的支持 

转载于:https://www.cnblogs.com/claireyuancy/p/6909319.html

你可能感兴趣的文章
MVC AJAX
查看>>
Google Map API V3开发(6) 代码
查看>>
Kafka初入门简单配置与使用
查看>>
第三章Git使用入门
查看>>
Amd,Cmd, Commonjs, ES6 import/export的异同点
查看>>
cocos2dx-Lua与Java通讯机制
查看>>
上下文管理器之__enter__和__exit__
查看>>
android3.2以上切屏禁止onCreate()
查看>>
winform文件迁移工具
查看>>
delphi DCC32命令行方式编译delphi工程源码
查看>>
paip.输入法编程----删除双字词简拼
查看>>
or1200下raw-os学习(任务篇)
查看>>
ZOJ - 3939 The Lucky Week(日期循环节+思维)
查看>>
小花梨的取石子游戏(思维)
查看>>
Ubuntu 18.04安装arm-linux-gcc交叉编译器
查看>>
.net core i上 K8S(一)集群搭建
查看>>
django drf 深入ModelSerializer
查看>>
Android---Menu菜单
查看>>
【资源导航】我所用到过的工具及下载地址
查看>>
监控Tomcat
查看>>