RecyclerView实现一个页面有多种item,每个item有多个view,并且可以让任意item的任意view自定义监听,通过接口方法进行触发操作
百度了很多贴子,看着大佬的博客,模仿尝试,最终都是以失败告终,api可能版本不一样,
毕竟博客大佬都是7~8前写的,日期新点的都是好几年前了,多次尝试,还是报出莫名其妙的错。
哎,忧伤。
翻阅各种资料,看了将近30多篇各种网站的贴子,从一开始的茫然,变成现在从容,因为我终于摸索出适合自己的方法了,
我要把完整的代码贴出来,供小白参考,不要再像我这样掉坑里了。
看效果图,看看是不是你要的效果


话不多说,我直接把完整的代码贴出来,
需要创建一个这样的泛型类出来装数据格式
package util;
public class ChatTwoType {
public static final int TYPE_ONE = 1;//类型1
public static final int TYPE_TWO = 2;//类型2
public int type;//item内容 类型
public int icon;
public String username;
public String message;
public ChatTwoType(int type, int icon, String username, String message){
this.type = type;
this.icon = icon;
this.username = username;
this.message = message;
}
public static int getTypeOne() {
return TYPE_ONE;
}
public static int getTypeTwo() {
return TYPE_TWO;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public int getIcon() {
return icon;
}
public void setIcon(int icon) {
this.icon = icon;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
然后,新建一个新的空的MainActivity和xml出来,最好用gradle,会自动帮你配置文件
xml文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/timg_2"
android:orientation="vertical"
tools:context=".MainTwoTypeAdaper"> <LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="7"> <android.support.v7.widget.RecyclerView
android:id="@+id/r1"
android:layout_width="match_parent"
android:layout_height="match_parent"
/> </LinearLayout> <LinearLayout
android:layout_width="match_parent"
android:layout_height="70dp" android:background="#FCFAFA">
<Button
android:id="@+id/b2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:layout_weight="1"
android:text="换边" /> <EditText
android:id="@+id/t1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:layout_weight="3" /> <Button
android:id="@+id/b1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:layout_weight="1"
android:text="发送" /> </LinearLayout> </LinearLayout>
效果如下图:

现在要去设置item啦,虽然是有多个不同的item,但是,实际是将所有都放在一个xml文件里,我新建了个xml文件,文件名为item1.xml,名字随便取,记得是哪个就行
item1.xml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp"
>
<!--padding是在控件内部的,margin是在控件外部的-->
<LinearLayout
android:id="@+id/iteml"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="left"> <LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_gravity="top"
>
<ImageView
android:id="@+id/item1i"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="4"
android:padding="10dp">
<TextView
android:id="@+id/item1t"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/chat3"
android:gravity="center"
/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout> <LinearLayout
android:id="@+id/itemr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="right" > <LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" /> <LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="4"
android:padding="10dp"
android:layout_gravity="right"
android:gravity="right"
>
<TextView
android:id="@+id/item2t"
android:layout_width="wrap_content"
android:layout_height="match_parent" android:background="@drawable/chat3"
android:gravity="center" />
</LinearLayout> <LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_gravity="top"
>
<ImageView
android:id="@+id/item2i"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:gravity="center" />
</LinearLayout> </LinearLayout> </LinearLayout>
效果如下图:

看看activity处的代码:
package com.example.love5; import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast; import java.util.ArrayList;
import java.util.List; import util.ChatAdaper;
import util.ChatTwoType;
import util.Myada; public class MainTwoTypeAdaper extends AppCompatActivity implements ChatAdaper.OnRecyclerItemClickListener{
private RecyclerView recyclerView;
private ChatAdaper adapter;
private List<ChatTwoType> list;
Button b1,b2;
TextView t1;
//识别是接收还是发送
private int user = 2;
private int rp = R.drawable.xiaren; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_two_type_adaper);
//实列父view
recyclerView = findViewById(R.id.r1); //实列化list
list = new ArrayList<>();
for (int i = 0 ; i < 20;i++){ // 加入初始数据,可以不加
list.add(new ChatTwoType(1, R.drawable.coffee, "cen", "吃饭没?\n\n\n5533\n44534"));
list.add(new ChatTwoType(2, R.drawable.xiaren, "666", "吃了,你呢")); } //垂直布局,默认底下添加
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager); //实列适配并且赋值,具体参数需要对应适配器方法里的参数顺序
adapter = new ChatAdaper(list);
//这是适配器的接口监听,如果没有,则会报错接口空指针异常
adapter.setOnRecyclerItemClickListener(this); recyclerView.setAdapter(adapter); t1 =findViewById(R.id.t1);
b1 = findViewById(R.id.b1);
b1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(!TextUtils.isEmpty(t1.getText())){ ChatTwoType c = new ChatTwoType(user,rp,"666",t1.getText().toString());
list.add(c);
//插入新数据,默认是参数就是要插入的位置,因为item排列的下标由0开始递增,所以要减一,如果想插入顶上,参数改成零就可以了
adapter.notifyItemInserted(list.size()-1);
//滚动到最底下,//若要滚动到顶上则把参数改成零就可以了
recyclerView.scrollToPosition(list.size()-1);
//编辑框清空
t1.setText("");
}
}
}); b2 = findViewById(R.id.b2);
b2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 换成接收
if(user == 2){
// 换成接收
rp = R.drawable.coffee;
user = 1; }else if(user == 1){
//换成发送
rp = R.drawable.xiaren;
user = 2;
} }
}); } private ImageView imageView,imageView2;
//用来实现item的头像图片宽与高大小相等,,获取任何view的宽高都要使用onWindowFocusChanged,否则获取的数据为null
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
imageView = findViewById(R.id.item1i);
int width = imageView.getWidth();
int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
imageView.measure(w, h);
ViewGroup.LayoutParams params = imageView.getLayoutParams();
int height = width;
params.height = height;
imageView.setLayoutParams(params); imageView2 = findViewById(R.id.item2i);
imageView2.setLayoutParams(params);
} //使用接口里的方法
public void a55(int u){
if(u == 1){
Toast.makeText(getApplicationContext(),"这是对方头像",Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(getApplicationContext(),"这是我的头像",Toast.LENGTH_SHORT).show();
} }
} 最后关键的一步,就是适配器的设置
代码如下:
package util; import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView; import com.example.love5.R; import java.util.List; public class ChatAdaper extends RecyclerView.Adapter<ChatAdaper.ViewHolder> {
private List<ChatTwoType> list;//数据源 //实列化所有item的所有控件,包括布局实列化
static class ViewHolder extends RecyclerView.ViewHolder { LinearLayout leftlayout;
LinearLayout rightlayout;
TextView lefttext;
TextView righttext;
ImageView lefyim;
ImageView rightim; public ViewHolder(View view) {
super(view);
leftlayout = view.findViewById(R.id.iteml);
lefttext = view.findViewById(R.id.item1t);
lefyim = view.findViewById(R.id.item1i);
rightlayout = view.findViewById(R.id.itemr);
righttext = view.findViewById(R.id.item2t);
rightim = view.findViewById(R.id.item2i);
}
} //activity传进来的数据,参数可以根据需要修改,需要context才传,不用则不传,参数与在activity实列适配器的参数对应
public ChatAdaper(List<ChatTwoType> list) {
this.list = list;
Log.d("ChatAdaper", "============" + list.get(0).getMessage()); } //计算有多少个item
@Override
public int getItemCount() {
return list == null ? 0 : list.size();
} //获取item并实列ViewHolder,把所有触发事件监控写出来,然后调用接口的方法执行你要做的事情,一般是用来传值到context然后再处理
@Override
public ChatAdaper.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//parent.getContext()可用context替换,前提是context需要由activity传进来
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item1, parent, false); final ViewHolder holder =new ViewHolder(view);
holder.lefyim.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("ChatAdaper","7777777777777777777777");
listener.a55(1);
}
}); holder.rightim.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("ChatAdaper","444444444444444444444444444444444444477");
listener.a55(2);
}
});
return holder;
} //绑定控件根据泛型类型的参数类型判断哪个布局显示,并将该布局的所有控件绑定相应的数据,不要的布局item一定要隐藏
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
ChatTwoType chatTwoType = list.get(position);
if (chatTwoType.getType() == ChatTwoType.TYPE_ONE) {
//收到的消息 //item布局显示
holder.leftlayout.setVisibility(View.VISIBLE);
//item布局隐藏
holder.rightlayout.setVisibility(View.GONE);
// 控件绑定相应的数据
holder.lefyim.setImageResource(chatTwoType.getIcon());
holder.lefttext.setText(chatTwoType.getMessage()); } else if (chatTwoType.getType() == ChatTwoType.TYPE_TWO) {
//item布局显示
holder.rightlayout.setVisibility(View.VISIBLE);
//item布局隐藏
holder.leftlayout.setVisibility(View.GONE);
// 控件绑定相应的数据
holder.rightim.setImageResource(chatTwoType.getIcon());
holder.righttext.setText(chatTwoType.getMessage());
} } //自定义实列
private ChatAdaper.OnRecyclerItemClickListener listener;
//实列接口setOnRecyclerItemClickListener要在activity的适配器实列后设置,用来给接口实列,如果没有会报空指针
public void setOnRecyclerItemClickListener(ChatAdaper.OnRecyclerItemClickListener listener) {
this.listener = listener;
}
//自定义接口名称,然后自定义接口里的方法,方法用于适配器监听触发调用,具体的方法内容在activity里,一般是用来从适配器传输数据到activity去,然后在activity里执行操作
public interface OnRecyclerItemClickListener {
//这里是适配器调用的方法可以返回值给activity,可以自定义
void a55(int u);
} }
RecyclerView实现一个页面有多种item,每个item有多个view,并且可以让任意item的任意view自定义监听,通过接口方法进行触发操作的更多相关文章
- PHP 页面跳转到另一个页面的多种方法方法总结
如何在PHP中从一个页面重定向到另外一个页面呢?这里列出了三种办法,供参考. 一.用HTTP头信息 也就是用PHP的HEADER函数.PHP里的HEADER函数的作用就是向浏览器发出由HTTP协议规定 ...
- Div里面载入另一个页面的实现(取代框架)(AJax)(转)
随着框架越来越不火了,HTML5就不对框架支持了,iframe也只有url了,Div就担当了此大任 DIV+CSS在页面部局确实也很让人满意,使用也更方便 今天突然遇到一个问题,那就是需要导入另一个页 ...
- Div里面载入另一个页面的实现(取代框架)(AJax)
随着框架越来越不火了,HTML5就不对框架支持了,iframe也只有url了,Div就担当了此大任 DIV+CSS在页面部局确实也很让人满意,使用也更方便 今天突然遇到一个问题,那就是需要导入另一个页 ...
- 01_6_SERVLET如何从上一个页面取得参数
01_6_SERVLET如何从上一个页面取得参数 1. sevlet实现 public void doGet(HttpServletRequest request, HttpServletRespon ...
- 关于vue事件监听的一个问题
由于新工作需要用vue,所以最近接触最多的也是vue,因为之前一直在用react,所以对于vue上手还是很快的.我也尽量找一些他们两个的异同点,除了多了一些辅助用的方法以外,最大的不同应该是对于组件间 ...
- 【转】ViewPager实现一个页面多个Item的显示
转自:http://billyyuan.iteye.com/blog/1941538 ViewPager实现一个页面多个Item的显示 博客分类: android 代码在: https://cod ...
- Android RecyclerView滑动监听,判断是否滑动到了最后一个item
项目中的需求,RecyclerView横向滑动列表,要有加载更多的功能,给RecyclerView设置一个滑动监听,在onScrolled方法中判断一下滑动方向,然后在onScrollStateCha ...
- 用RecyclerView做一个小清新的Gallery效果
一.简介 RecyclerView现在已经是越来越强大,且不说已经被大家用到滚瓜烂熟的代替ListView的基础功能,现在RecyclerView还可以取代ViewPager实现Banner效果,当然 ...
- 用RecyclerView做一个小清新的Gallery效果 - Ryan Lee的博客
一.简介 RecyclerView现在已经是越来越强大,且不说已经被大家用到滚瓜烂熟的代替ListView的基础功能,现在RecyclerView还可以取代ViewPager实现Banner效果,当然 ...
随机推荐
- 最短寻道优先算法----SSTF算法
请珍惜小编劳动成果,该文章为小编原创,转载请注明出处. 该算法选择这样的进程,其要求访问的磁道与当前磁头所在的磁道距离最近,以使每次的寻道时间最短 java代码实现如下: import java.ut ...
- [爬虫]Windows下如何安装python第三方库lxml
lxml是个非常有用的python库,它可以灵活高效地解析xml与BeautifulSoup.requests结合,是编写爬虫的标准姿势. 但是,当lxml遇上Windows,简直是个巨坑.掉在安装陷 ...
- server.go 源码阅读
; i < conn.retries(); i++ { r.conf.addr = conn.addr() listener, err = net.Listen( ...
- SQL Server 中如何做到连续时间段的拆分?
今天在工作中遇到了一个很实际的问题,客户在OA接口的员工休假中间表中提供了连续时间段的休假记录,例如: 张三,2018-12-1 ~2018-12-31 ,病假,31天.这样带来的问题是,如果我需要统 ...
- 用Fundebug插件记录网络请求异常
在服务端,不管我们使用Node.js.Java.PHP还是Python等等,都会用日志以文本的形式记录请求以及报错信息.这个对于后端做事后分析是很有用的. 另一方面,前端有时候出问题其实是因为后端接口 ...
- RabbitMQ windows本地安装
1: 安装RabbitMQ需要先安装Erlang语言开发包.下载地址 http://www.erlang.org/download.html 配置环境变量 ERLANG_HOME C:\Program ...
- 认识容器和Docker(一)
前言: 这句话应该是开发人员经常挂在嘴边的吧! “在我的机器上是正常工作的啊,MD,怎么到你这就不行了?” 开发人员就会联想到: 1. 肯定是你环境有问题: 2. 要么就是你个傻*不会用吧: 带着这句 ...
- Vue 进阶之路(六)
上篇文章我们分析了一下 vue 中的条件渲染,本篇我们说一下 vue 中的列表渲染和 set 方法. <!DOCTYPE html> <html lang="en" ...
- mybatis入门系列一之创建mybatis程序
Mybatis基础系列一 创建第一个mybatis程序 需要配置项 1. 在conf.xml的需要配置配置两个标签数据库连接和mapper,xml文件加载信息 <-- 进行数据库环境参数的配置 ...
- DRUID连接池配置详情
DRUID介绍 DRUID是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0.DBCP.PROXOOL等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针 ...