转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38173061 。本文出自:【张鸿洋的博客】

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

1、RecyclerView的基本使用方法

首先主Activity的布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" > <android.support.v7.widget.RecyclerView
android:id="@+id/id_recyclerview_horizontal"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_centerVertical="true"
android:background="#FF0000"
android:scrollbars="none" /> </RelativeLayout>

Item的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="120dp"
android:layout_height="120dp"
android:background="@drawable/item_bg02" > <ImageView
android:id="@+id/id_index_gallery_item_image"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_margin="5dp"
android:scaleType="centerCrop" /> <TextView
android:id="@+id/id_index_gallery_item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/id_index_gallery_item_image"
android:layout_centerHorizontal="true"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:textColor="#ff0000"
android:text="some info"
android:textSize="12dp" /> </RelativeLayout>

数据适配器:

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<GalleryAdapter.ViewHolder>
{ private LayoutInflater mInflater;
private List<Integer> mDatas; public GalleryAdapter(Context context, List<Integer> 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<Integer> 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<Integer>(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<GalleryAdapter.ViewHolder>
{ /**
* 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<Integer> mDatas; public GalleryAdapter(Context context, List<Integer> 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实现滚动时内容联动

首先改动下布局:

布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <FrameLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" > <ImageView
android:id="@+id/id_content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:layout_margin="10dp"
android:scaleType="centerCrop"
android:src="@drawable/ic_launcher" />
</FrameLayout> <com.example.zhy_horizontalscrollview03.MyRecyclerView
android:id="@+id/id_recyclerview_horizontal"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_gravity="bottom"
android:background="#FF0000"
android:scrollbars="none" /> </LinearLayout>

加入一个显示大图的区域。把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<Integer> 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<Integer>(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有了一定的认识,甚至对于怎样改造一个控件也多了一份了解~~

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

源代码点击下载

Android 自己定义RecyclerView 实现真正的Gallery效果的更多相关文章

  1. Android上使用RecyclerView实现顶部悬浮标题效果的Sticky Title View

    目前很多的项目都在使用顶部悬浮标题的效果,很明显,这的确是一个比较人性化,用户体验效果比较好的UI交互效果,对于这个效果,有很多种实现方式,如果说要用RecyclerView来实现一个分类信息展示,并 ...

  2. Android 自定义RecyclerView 实现真正的Gallery效果

    http://blog.csdn.net/lmj623565791/article/details/38173061

  3. Android 自己定义ScrollView ListView 体验各种纵向滑动的需求

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38950509.本文出自[张鸿洋的博客] 1.概述 群里的一个哥们有个需求是这种: ...

  4. Android 高级编程 RecyclerView 控件的使用

    RecyclerView 是Android 新添加的一个用来取代ListView的控件,它的灵活性与可替代性比listview更好. 看一下继承关系: ava.lang.Object    ↳ and ...

  5. Android学习之RecyclerView

    RecyclerView是android-support-v7-21版本号中新增的一个Widget,官方介绍RecyclerView 是 ListView 的升级版本号,更加先进和灵活. 开发环境 - ...

  6. android开发学习 ------- RecyclerView多类型实例

    实现RecyclerView多类型的实例:效果如下图所示 public class CarFragment extends Fragment{ private View view; private R ...

  7. 用RecyclerView做一个小清新的Gallery效果

    一.简介 RecyclerView现在已经是越来越强大,且不说已经被大家用到滚瓜烂熟的代替ListView的基础功能,现在RecyclerView还可以取代ViewPager实现Banner效果,当然 ...

  8. Android最新组件RecyclerView,替代ListView

    转载请注明出处:http://blog.csdn.net/allen315410/article/details/40379159 万众瞩目的android最新5.0版本号不久前已经正式公布了,对于我 ...

  9. Android控件RecyclerView的基本用法

    Android控件RecyclerView的基本用法 转 https://www.jianshu.com/p/e71a4b73098f   github: https://github.com/Cym ...

随机推荐

  1. maven 创建web项目出错

    错误的信息: .m2/repository/org/apache/maven/archetypes/maven-archetype-webapp/maven-metadata-central.xml ...

  2. validate命令---rman进行备份和回复的验证

    rman作为oracle备份与恢复工具,为我们提供了强大的功能.当中包含对数据文件的物理和逻辑检測以及备份文件的有效性检測. 首先.来看一下rman对数据文件的检測. 我们知道,rman在备份数据时, ...

  3. 第6章7节《MonkeyRunner源代码剖析》Monkey原理分析-事件源-事件源概览-注入按键事件实例

    在事件生成并放入到命令队列后,Monkey类的runMonkeyCycles就会去调用相应事件源的getNextEvent来获的事件来运行事件注入,那么这一小节我们通过MonkeyKeyEvent这个 ...

  4. mysqlbinlog高速遍历搜索记录

    目标,开发者说有个数据莫名其妙加入了.可是不知道是从哪里加入的.并且应用功能里面不应该加入这种数据,为了查清楚来源,所以我就准备去binlog里面找了.可是binlog有好几个月的数,我这样一个个my ...

  5. Spring《三》ref 引用其他bean

    local属性 1.被引用id必须在同一个xml中. 2.被引用id必须使用id命名. 优点提前检查所使用的bean id是否正确. Bean属性 1.Bean指定的id可以在不同的xml中. 2.B ...

  6. redis简单的事务

    Redis与 mysql事务的对比 占位 Mysql Redis 开启 start transaction muitl 语句 普通sql 普通命令 失败 rollback 回滚 discard 取消 ...

  7. 尝试实现bootstrap3网格系统

    这是一篇搁置了很久的博文,个人实现的关键代码如下: // 这是用sass实现的,只是大致实现了网格系统和offset的功能 $size_list: ( xs: 0, sm: 576, md: 992, ...

  8. MySQL 5.6.26 通过frm & ibd 恢复数据过程

    在A服务器上创建数据库yoonroot(yoon)> show create table yoon\G*************************** 1. row *********** ...

  9. CodeIgniter 相关资源

    CodeIgniter ci 如果需要扩展多个base Controller,譬如一个 core/MY_Controller表示基本Controller,一个  core/MY_AuthControl ...

  10. VUE使用中踩过的坑

    前言 vue如今可谓是一匹黑马,github star数已居第一位!前端开发对于vue的使用已经越来越多,它的优点就不做介绍了,本篇是我对vue使用过程中以及对一些社区朋友提问我的问题中做的一些总结, ...