android RecycleView复杂多条目的布局

用RecycleView来实现布局形式,默认只能指定一种布局格式,但是实际中我们的布局经常会用到多种类型的布局方式。如何实现呢?

今天来说下常用的2钟方式。

第一种:

通过自定义addHeadView方法来添加头布局

RecycleViewWithHead.java

import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
import android.support.v7.widget.RecyclerView;
import android.view.View;

public class RecycleViewWithHead extends Activity {

	private RecyclerView rcv;
	// 当前的条目是recyclerView的头布局
	public static final int HEADER_RECYCLER_VIEW_ITEM = 0;
	// 当前的条目是普通recyclerView的条目
	public static final int NORMAL_RECYCLER_VIEW_ITEM = 1;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_recycle);
		rcv = (RecyclerView) findViewById(R.id.rcv);
		// 设置布局管理
		GridLayoutManager manager = new GridLayoutManager(this, 2);
		// 设置布局管理一条数据占用几行,如果是头布局则头布局自己占用一行
		manager.setSpanSizeLookup(new SpanSizeLookup() {
			@Override
			public int getSpanSize(int postion) {
				if (postion == 0) {
					return 2;
				} else {
					return 1;
				}
			}
		});
		rcv.setLayoutManager(manager);
		MyRecycleAdapter adapter = new MyRecycleAdapter(
				RecycleViewWithHead.this, 20);
		View view = View.inflate(this, R.layout.head, null);
		adapter.addHeadView(view);
		rcv.setAdapter(adapter);
	}
}


布局文件activity_recycle.xml

<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/rcv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />


</RelativeLayout>


头布局文件head.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:id="@+id/iv_head"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_margin="10dp"
        android:src="@drawable/head" />

    <TextView
        android:id="@+id/tv_head"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@+id/iv_head"
        android:layout_toRightOf="@+id/iv_head"
        android:text="这是一张熊猫的图片" />

    <ImageView
        android:id="@+id/iv_head_bottom"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/iv_head"
        android:layout_toRightOf="@+id/iv_head"
        android:src="@drawable/type" />

</RelativeLayout>



适配器MyRecycleAdapter.java

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Toast;

public class MyRecycleAdapter extends
		RecyclerView.Adapter<MyRecycleAdapterHolder> {

	private View headView;
	private Context mContext;
	private int count;

	MyRecycleAdapter(Context mContext, int count) {
		this.count = count;
		this.mContext = mContext;
	}

	/**
	 * 设置数据源总的条目
	 */
	@Override
	public int getItemCount() {
		//返回条目数加头布局个数
		return count + 1;
	}

	@Override
	public void onBindViewHolder(MyRecycleAdapterHolder holder,
			final int position) {
		int itemViewType = getItemViewType(position);
		// 头部
		if (itemViewType == RecycleViewWithHead.HEADER_RECYCLER_VIEW_ITEM) {
			return;
		} else if (itemViewType == RecycleViewWithHead.NORMAL_RECYCLER_VIEW_ITEM) {//普通条目
			holder.iv_item_icon.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					Toast.makeText(mContext, (position - 1) + "", 0).show();
				}
			});
		}

	}

	@Override
	public MyRecycleAdapterHolder onCreateViewHolder(ViewGroup parent,
			int viewType) {
		View root = null;
		if (viewType == RecycleViewWithHead.HEADER_RECYCLER_VIEW_ITEM) {
			root = headView;
		} else {
			root = LayoutInflater.from(mContext).inflate(R.layout.item, parent,
					false);
		}
		return new MyRecycleAdapterHolder(root, viewType);
	}

	/**
	 * 添加自定义头部
	 */
	public void addHeadView(View view) {
		this.headView = view;
	}

	@Override
	public int getItemViewType(int position) {

		if (position == 0) {
			return RecycleViewWithHead.HEADER_RECYCLER_VIEW_ITEM;
		} else {
			return RecycleViewWithHead.NORMAL_RECYCLER_VIEW_ITEM;
		}
	}
}


普通条目的布局文件item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_list"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="2dp"
    android:layout_marginRight="2dp"
    android:layout_marginTop="5dp"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/iv_item_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/item" />

    <TextView
        android:id="@+id/tv_item"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="5dp"
        android:text="这是一只熊猫" />

</LinearLayout>



普通条目的ViewHolder

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

public class MyRecycleAdapterHolder extends RecyclerView.ViewHolder{
	
	public ImageView iv_item_icon;
	public TextView tv_item;
	public MyRecycleAdapterHolder(View itemView) {
		super(itemView);
	}
	public MyRecycleAdapterHolder(View itemView,int viewType) {
		super(itemView);
		initView(itemView,viewType);
	}
	private void initView(View itemView, int viewType) {
		iv_item_icon = (ImageView) itemView.findViewById(R.id.iv_item_icon);
		tv_item = (TextView) itemView.findViewById(R.id.tv_item);
	}

}

效果图:




还有一种情况类似于淘宝的商品展示我们可以切换每行显示的数量,其实也很简单

先看下要实现的效果:


我先说下大致的实现思路:

1.给adapter设置一个当前显示多行还是单行的标记。

2.每次切换视图时重置标记,并重置RecycleView的LayoutManager。

3.调用adapter.notifyItemRangeChanged(2, adapter.getItemCount());(第一个参数是动画开始的位置索引)

好了再来看下RecycleViewWithHead.java

import com.example.myrecycleviewdemo.adapter.MyRecycleAdapter;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;

public class RecycleViewWithHead extends Activity implements OnClickListener {

	private RecyclerView rcv;
	// 当前的条目是recyclerView的头布局
	public static final int HEADER_RECYCLER_VIEW_ITEM = 0;
	// 当前的条目是普通recyclerView的条目
	public static final int NORMAL_RECYCLER_VIEW_ITEM = 1;
	// 一行显示一个
	public static final int RECYCLER_VIEW_ITEM_SINGLE = 3;
	// 一行显示两个
	public static final int RECYCLER_VIEW_ITEM_DOUBLE = 4;
	private ImageView iv_switch;// 视图转换
	private MyRecycleAdapter adapter;
	private GridLayoutManager manager;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_recycle);
		rcv = (RecyclerView) findViewById(R.id.rcv);
		iv_switch = (ImageView) findViewById(R.id.iv_switch);
		iv_switch.setOnClickListener(this);
		manager = new GridLayoutManager(this, 2);
		// 设置布局管理一条数据占用几行,如果是头布局则头布局自己占用一行
		manager.setSpanSizeLookup(new SpanSizeLookup() {
			@Override
			public int getSpanSize(int postion) {
				if (postion == 0) {
					return 2;
				} else {
					return 1;
				}
			}
		});
		rcv.setLayoutManager(manager);
		adapter = new MyRecycleAdapter(RecycleViewWithHead.this, 20);
		View view = View.inflate(this, R.layout.head, null);
		// 设置当前ViewType
		adapter.setSpanSize(RecycleViewWithHead.RECYCLER_VIEW_ITEM_DOUBLE);
		adapter.addHeadView(view);
		rcv.setAdapter(adapter);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.iv_switch:
			changeRecycleViewList();
			break;

		default:
			break;
		}

	}

	/**
	 * 改变RecycleView的显示列数
	 */
	private void changeRecycleViewList() {
		if (adapter != null) {
			int spanSize = adapter.getSpanSize();
			// 当前一行显示一列
			if (spanSize == RecycleViewWithHead.RECYCLER_VIEW_ITEM_SINGLE) {
				manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
					@Override
					public int getSpanSize(int position) {
						if (adapter.getItemViewType(position) == RecycleViewWithHead.HEADER_RECYCLER_VIEW_ITEM) {
							return 2;
						} else {
							return 1;

						}
					}
				});
				adapter.setSpanSize(RecycleViewWithHead.RECYCLER_VIEW_ITEM_DOUBLE);
			}
			// 当前一行显示两列
			else if (spanSize == RecycleViewWithHead.RECYCLER_VIEW_ITEM_DOUBLE) {
				manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
					@Override
					public int getSpanSize(int position) {
						if (adapter.getItemViewType(position) == RecycleViewWithHead.HEADER_RECYCLER_VIEW_ITEM) {
							return 2;
						} else {
							return 2;
						}
					}
				});
				adapter.setSpanSize(RecycleViewWithHead.RECYCLER_VIEW_ITEM_SINGLE);
			}
			// 第一个参数是动画开始的位置索引
			adapter.notifyItemRangeChanged(2, adapter.getItemCount());
		}
	}
}


布局文件activity_recycle.xml

<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/rcv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    
    <ImageView 
        android:id="@+id/iv_switch"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
		android:layout_alignParentTop="true"
        android:layout_alignParentRight="true"
        android:layout_margin="20dp"
        android:src="@drawable/more"
        />

</RelativeLayout>


适配器MyRecycleAdapter.java

import com.example.myrecycleviewdemo.R;
import com.example.myrecycleviewdemo.RecycleViewWithHead;
import com.example.myrecycleviewdemo.R.layout;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Toast;

public class MyRecycleAdapter extends
		RecyclerView.Adapter<MyRecycleAdapterHolder> {

	public View headView;
	public Context mContext;
	public int count;
	private int spanSize;// 当前每行显示几列

	public MyRecycleAdapter(Context mContext, int count) {
		this.count = count;
		this.mContext = mContext;
	}

	/**
	 * 设置数据源总的条目
	 */
	@Override
	public int getItemCount() {
		// 返回条目数加头布局个数
		return count + 1;
	}

	@Override
	public void onBindViewHolder(MyRecycleAdapterHolder holder,
			final int position) {
		int itemViewType = getItemViewType(position);
		// 头部
		if (itemViewType == RecycleViewWithHead.HEADER_RECYCLER_VIEW_ITEM) {
			return;
		} else {// 普通条目
			if (itemViewType == RecycleViewWithHead.RECYCLER_VIEW_ITEM_DOUBLE) {// 一行两列视图
				holder.iv_item_icon.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						Toast.makeText(mContext, "2列," + (position - 1) + "", 0)
								.show();
					}
				});
			} else if (itemViewType == RecycleViewWithHead.RECYCLER_VIEW_ITEM_SINGLE) {// 一行一列视图
				holder.iv_item_icon_single.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						Toast.makeText(mContext,"单列," + (position - 1) + "", 0).show();
					}
				});
			}
		}
	}

	@Override
	public MyRecycleAdapterHolder onCreateViewHolder(ViewGroup parent,
			int viewType) {
		View root = null;
		// 头部
		if (viewType == RecycleViewWithHead.HEADER_RECYCLER_VIEW_ITEM) {
			root = headView;
		} else {// 普通条目
			/** 一行显示一条 */
			if (viewType == RecycleViewWithHead.RECYCLER_VIEW_ITEM_SINGLE) {
				root = LayoutInflater.from(mContext).inflate(R.layout.item_single, parent, false);
			}
			/** 一行显示两条 */
			else {
				root = LayoutInflater.from(mContext).inflate(R.layout.item_double, parent, false);
			}
		}
		return new MyRecycleAdapterHolder(root, viewType);
	}

	/**
	 * 添加自定义头部
	 */
	public void addHeadView(View view) {
		this.headView = view;
	}

	@Override
	public int getItemViewType(int position) {

		if (position == 0) {
			return RecycleViewWithHead.HEADER_RECYCLER_VIEW_ITEM;
		} else {
			/** 一行显示一条 */
			if (spanSize == RecycleViewWithHead.RECYCLER_VIEW_ITEM_SINGLE) {
				return RecycleViewWithHead.RECYCLER_VIEW_ITEM_SINGLE;
				/** 一行显示两条 */
			} else {
				return RecycleViewWithHead.RECYCLER_VIEW_ITEM_DOUBLE;
			}
		}
	}

	public int getSpanSize() {
		return spanSize;
	}

	public void setSpanSize(int spanSize) {
		this.spanSize = spanSize;
	}
}


普通条目的ViewHolder

import com.example.myrecycleviewdemo.R;
import com.example.myrecycleviewdemo.R.id;
import com.example.myrecycleviewdemo.RecycleViewWithHead;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

public class MyRecycleAdapterHolder extends RecyclerView.ViewHolder{
	//一行两列视图
	public ImageView iv_item_icon;
	public TextView tv_item;
	
	//一行一列视图
	public ImageView iv_item_icon_single;
	public TextView tv_item_single;
	
	public MyRecycleAdapterHolder(View itemView) {
		super(itemView);
	}
	public MyRecycleAdapterHolder(View itemView,int viewType) {
		super(itemView);
		initView(itemView,viewType);
	}
	private void initView(View itemView, int viewType) {
		if(viewType == RecycleViewWithHead.RECYCLER_VIEW_ITEM_DOUBLE){
			iv_item_icon = (ImageView) itemView.findViewById(R.id.iv_item_icon);
			tv_item = (TextView) itemView.findViewById(R.id.tv_item);
		}else if(viewType == RecycleViewWithHead.RECYCLER_VIEW_ITEM_SINGLE){
			iv_item_icon_single = (ImageView) itemView.findViewById(R.id.iv_item_icon_single);
			tv_item_single = (TextView) itemView.findViewById(R.id.tv_item_single);
		}
	}
}

头布局文件head.xm没有任何变化

条目的布局拆分为2个item_double.xml和item_single.xml

item_double.xml和之前的item.xml一样。


item_single.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_list"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="2dp"
    android:layout_marginRight="2dp"
    android:layout_marginTop="5dp"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/iv_item_icon_single"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/item" />

    <TextView
        android:id="@+id/tv_item_single"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginTop="5dp"
        android:text="这是一只熊猫" />

</LinearLayout>


源码地址:http://download.csdn.net/detail/linder_qzy/9487799



本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。
下面异常是属于Runtime Exception 的是(abcd)(多选) A、ArithmeticException B、IllegalArgumentException C、NullPointerException D、BufferUnderflowException 解析: Java提供了两类主要的异常:runtime exception和checked exception。checked 异常也就是我们经常遇到的IO异常,以及SQL异常都是这种异常。对于这种异常,JAVA编译器强制要求我们必需对出

CloudBusiness开发文档 - 2016-04-12 14:04:03

一 iOS集成指南 1.1 导入SDK 第一步:先下载IM对应的sdk,解压之后目录如图所示例: Yuntx_IMLib_V5.x.xr.a库是静态库,Manager文件夹是主调函数声明,Delegate文件夹是回调函数声明。 第二步:然后导入sdk。将解压后的文件夹(Yuntx_IMLib_SDK)拖入您的工程中,并勾选上Destination,如图所示: 1.2、设置工程属性 向Build Phases - Link Binary With Libraries 中添加系统依赖库,操作步骤如下所示: 按
0 框架效果图 一 讲解顺序 1 标题部分 2 内容显示部分 3 完善代码 4 知识补充 二 内容显示部分解析 1 搭建: 通过观察该部分运行情况,支持上下滑动,同时也支持左右滑动 —- 1.1 结论: 父控件采用UIScrollView;子控件采用五个tableView 2 分析一: 考虑内容显示的数据量比较大 —- 2.1 做法: tableView采用循环利用 3 tableView的排列顺序: 设置scrollerView的偏移量为5个tableView的宽度(contentSize),将tabl
前言: iOS的内存管理机制ARC和MRC是程序员参加面试基本必问的问题,也是考察一个iOS基本功是 否扎实的关键,这样深入理解内存管理机制的重要性就不言而喻了。 iOS内存管理机制发展史 iOS 5以前 :MRC(手动引用计数) iOS 5及以后:ARC (自动引入计数) MRC机制时代 “谁开辟申请,谁及时合理释放” 面对自己申请的内存空间是要及时进行回收的: 不及时释放会造成什么结果? 对象存储在栈上,可能会大量的占用内存,内存不足造成程序闪退 (也就是所说的内存泄露) 不合理释放会造成什么后果?
一、 默认快捷键 提高开发工具使用效率,首先必谈的就是快捷键了, 首先, 在IDE自带的快捷键中,常用的也不过二十来个,对于这些常用的操作,我们当然是希望按键越少越好,能按1个键完成不用2个键,能2个键完成坚决不用3个键,然而IDE默认的按键并不完全符合我们的要求,这个时候当然就是改改改啦。 接下来按照各类操作来介绍: 补全+修正+提示(必备) 操作 按键 备注 自动修正 Alt + Enter 相当于eclipse的Ctrl + 1 格式化代码 Ctrl + Alt + L 相当于eclipse的Ctr
官方文档原文地址 应用程序原理 Android应用程序是通过Java编程语言来写。Android软件开发工具把你的代码和其他数据、资源文件一起编译、打包成一个APK文件,这个文档以.apk为后缀,保存了一个Android应用程序所有的内容,Android设备通过它来安装对应的应用。 一旦安装到设备上,每个Android应用程序就运行在各自独立的安全沙盒中: Android系统是一个多用户的Linux系统,每一个应用都是一个用户。 Android系统默认会给每个应用分配一个唯一的用户ID(这个ID只被系统使
本文首发: http://prototypez.github.io/2016/04/10/rxjava-common-mistakes-1/ 转载请注明出处 准备写这篇文章的时候看了下 RxJava 在 Github 上已经 12000+ 个 star 了,可见火爆程度,自己使用 RxJava 也已经有一小段时间。最初是在社区对 RxJava 一片赞扬之声下,开始使用 RxJava 来代替项目中一些简单异步请求,到后来才开始接触一些高级玩法,这中间阅读别人的代码加上自己踩的坑,慢慢积累了一些经验,很多都是
目录 目录 概述 处理流程 裁剪方式 裁剪原理 裁剪流程 图片加载 图片绘制 获取屏幕的大小 计算图片绘制区域 绘制图片 计算裁剪框 绘制裁剪框 裁剪操作 计算实际裁剪区域 裁剪并保存图片 关于移动的限制 关于缩放的限制 使用方式 源码 裁剪类源码 裁剪View源码 接口源码 GitHub地址 概述 处理流程 裁剪方式 图片的裁剪方式有很多种,最常见的有两种吧. 但不管是哪什么类型的裁剪方式,至少需要处理的有以下两个点: 图片显示 裁剪框显示 裁剪方式的不同在于以上两部分的处理方式不同而不同. 系统默认方
上一篇我们简单地说了一下Android java层的基本框架。接下来我们就来聊一下在android中音量控制的相关内容。 1.音量定义 在Android中,音量的控制与流类型是密不可分的,每种流类型都独立地拥有自己的音量设置,各种流类型的音量是互不干扰的,例如音乐音量、通话音量就是相互独立的。Andorid当前在AudioSystem.java默认有10种流类型(见下表列二)。既然Android当中有10种流类型,每种流类型的音量都是相互独立的,所以在默认音量方面,Android也给每种流类型初始化了一个
1. 手机适配方式 1.1 适配方式之 dp 名词解释 : 分辨率:eg:480*800,1280*720。表示物理屏幕区域内像素点的总和。(切记:跟屏幕适配没有任何关系) 因为我们既可以把 1280*720 的分辨率做到 4.0 的手机上面。我也可以把 1280*720 的分辨率做到 5.0 英寸的手机 上面,如果分辨率相同,屏幕越小越清晰 px(pix) : 像素, 就是屏幕中最小的一个显示单元 dip(像素密度) : 即每英寸屏幕所拥有的像素数,像素密度越大,显示画面细节就越加丰富 计算公式 : 像