前面一篇介紹了RecyclerView的下拉刷新和上拉加載垦巴,今天介紹非樹狀列表的展開和隱藏功能。數(shù)據(jù)是在同一級列表返回矿咕。
項(xiàng)目說明:
一,使用的AndroidStudio版本為3.2.1丐怯,gradle-4.6
二,使用的RecyclerView的adapter是BaseRecyclerViewAdapterHelper,github上對應(yīng)的地址如下
github地址為:https://github.com/CymChad/BaseRecyclerViewAdapterHelper
對應(yīng)的簡書說明地址為:http://www.reibang.com/p/b343fcff51b0
展示效果:
jsrecyclerview2.gif
為什么寫這篇簡書的說明和坑點(diǎn):
一,這其實(shí)是一個(gè)很小的功能點(diǎn)庶诡,但是這其中還是有很多坑,所以寫這篇簡書來記錄和分享給其他需要的人咆课。
二,列表數(shù)據(jù)超過10條的時(shí)候,點(diǎn)擊第一條的數(shù)據(jù)扯俱,會(huì)造成第11條數(shù)據(jù)也會(huì)有相應(yīng)的改變书蚪。
三,列表加載了數(shù)據(jù),在向上滑動(dòng)的過程中迅栅,明明是展開的狀態(tài)殊校,但是他會(huì)因?yàn)榱斜淼闹赜脤?dǎo)致數(shù)據(jù)錯(cuò)亂,會(huì)重新顯示隱藏狀態(tài)读存。
現(xiàn)在正式開始
1为流,基本配置如依賴包呕屎,下拉刷新功能等在RecyclerView系列(二)中已經(jīng)說明,不做描述敬察,重點(diǎn)說坑點(diǎn)以及實(shí)現(xiàn)方法秀睛。
2,一般在實(shí)現(xiàn)每一個(gè)item的點(diǎn)擊事件的時(shí)候使用的方法如下:在對應(yīng)的activity中使用對應(yīng)的adapter實(shí)現(xiàn)點(diǎn)擊事件(如下)莲祸,這樣做的弊端是拿不到每一個(gè)你所點(diǎn)擊的item所對應(yīng)的控件蹂安,而且傳參中View view對應(yīng)的view也無法拿到外部view對應(yīng)的id,從而無法控制外部view的顯示和隱藏锐帜。
//6.1田盈,給recyclerView的每一個(gè)子列表添加點(diǎn)擊事件
// mTestAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
//// @Override
//// public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
//// Toast.makeText(MainActivity.this, "我點(diǎn)擊了第" + position + "個(gè)子view",
//// Toast.LENGTH_SHORT).show();
//// }
//// });
3,正確做法是如下中6.2所示缴阎,使用對應(yīng)的recyclerview實(shí)現(xiàn)點(diǎn)擊事件允瞧,點(diǎn)擊事件中更新實(shí)例中自定義的isShow參數(shù)的狀態(tài),這個(gè)isShow是對應(yīng)到每個(gè)item的蛮拔,所以不會(huì)串瓷式。然后 mTestAdapter.notifyDataSetChanged();更新數(shù)據(jù)。對應(yīng)的適配器中就會(huì)刷新數(shù)據(jù)语泽。
package com.mumu.jsrecyclerview2;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.listener.OnItemChildClickListener;
import com.scwang.smartrefresh.layout.SmartRefreshLayout;
import com.scwang.smartrefresh.layout.api.RefreshLayout;
import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener;
import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public class MainActivity extends AppCompatActivity {
@BindView(R.id.rv_test)
RecyclerView rvTest;
@BindView(R.id.srl_test)
SmartRefreshLayout srlTest;
private TestAdapter mTestAdapter;
private ArrayList<TestEntity.ResultBean.ListBean> mTestList;
private Unbinder unbinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
unbinder = ButterKnife.bind(this);
initView();
}
private void initView() {
//初始化的時(shí)候默認(rèn)沒有數(shù)據(jù)贸典,顯示空的布局
getData(1);
refreshView();
smartRefreshView();
}
@Override
protected void onDestroy() {
super.onDestroy();
unbinder.unbind();
}
/**
* 刷新消息列表
*/
private void refreshView() {
//1,加載空布局文件,便于第五步適配器在沒有數(shù)據(jù)的時(shí)候加載
View emptyView = View.inflate(this, R.layout.empty_view, null);
//2踱卵,設(shè)置LayoutManager,LinearLayoutManager表示豎直向下
rvTest.setLayoutManager(new LinearLayoutManager(this));
//3廊驼,初始化一個(gè)無數(shù)據(jù)的適配器
mTestAdapter = new TestAdapter();
//4,綁定recyclerView和適配器
rvTest.setAdapter(mTestAdapter);
//5惋砂,給recyclerView設(shè)置空布局
mTestAdapter.setEmptyView(emptyView);
//6.1妒挎,給recyclerView的每一個(gè)子列表添加點(diǎn)擊事件
// mTestAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
//// @Override
//// public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
//// Toast.makeText(MainActivity.this, "我點(diǎn)擊了第" + position + "個(gè)子view",
//// Toast.LENGTH_SHORT).show();
//// }
//// });
//6.2,給recyclerView的每一個(gè)子列表添加點(diǎn)擊事件
// TODO: 2019/1/10 這不能使用上面6.1的點(diǎn)擊事件的方法西饵,使用以上方法會(huì)導(dǎo)致點(diǎn)擊混亂酝掩,滑動(dòng)導(dǎo)致已經(jīng)展開的item隱藏
rvTest.addOnItemTouchListener(new OnItemChildClickListener() {
@Override
public void onSimpleItemChildClick(BaseQuickAdapter adapter, View view, int position) {
switch (view.getId()) {
case R.id.rl_item_title:
// TODO: 2019/1/11 1,點(diǎn)擊按鈕的時(shí)候更新在實(shí)例中對應(yīng)的isShow數(shù)據(jù)
if (mTestList.get(position).isShow()) {
mTestList.get(position).setShow(false);
Toast.makeText(MainActivity.this,"第"+position+"個(gè)隱藏",Toast.LENGTH_SHORT).show();
} else {
mTestList.get(position).setShow(true);
Toast.makeText(MainActivity.this,"第"+position+"個(gè)展開",Toast.LENGTH_SHORT).show();
}
// TODO: 2019/1/11,2眷柔,適配器更新數(shù)據(jù)期虾,刷新列表,更新狀態(tài)
mTestAdapter.notifyDataSetChanged();
break;
default:
break;
}
}
});
}
/**
* MainActivity中增加下拉刷新和上拉加載的監(jiān)聽方法
*/
private void smartRefreshView() {
srlTest.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() {
@Override
public void onRefresh(@NonNull RefreshLayout refreshLayout) {
//下拉刷新,一般添加調(diào)用接口獲取數(shù)據(jù)的方法
getData(2);
refreshLayout.finishRefresh();
}
@Override
public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
//上拉加載驯嘱,一般添加調(diào)用接口獲取更多數(shù)據(jù)的方法
getData(3);
refreshLayout.finishLoadMoreWithNoMoreData();
}
});
}
/**
* 獲取數(shù)據(jù)的方法
* 該方法純屬展示各種效果镶苞,實(shí)際應(yīng)用時(shí)候請自己根據(jù)需求做判斷即可
*
* @param mode 模式:1為剛開始進(jìn)來加載數(shù)據(jù) 空數(shù)據(jù) 2為下拉刷新 3為上拉加載
*/
private void getData(int mode) {
//添加臨時(shí)數(shù)據(jù),一般直接從接口獲取
switch (mode) {
case 1:
break;
case 2:
mTestList = new ArrayList<>();
for (int i = 0; i < 15; i++) {
mTestList.add(new TestEntity.ResultBean.ListBean("我有一個(gè)小狗", "我有一個(gè)小狗我有一個(gè)小狗我有一個(gè)小狗我有一個(gè)小狗我有一個(gè)小狗"));
}
//更新數(shù)據(jù)
mTestAdapter.setNewData(mTestList);
break;
case 3:
for (int i = 0; i < 15; i++) {
mTestList.add(new TestEntity.ResultBean.ListBean("我有一個(gè)小狗", "我有一個(gè)小狗我有一個(gè)小狗我有一個(gè)小狗我有一個(gè)小狗我有一個(gè)小狗"));
}
mTestAdapter.setNewData(mTestList);
break;
default:
mTestList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
mTestList.add(new TestEntity.ResultBean.ListBean("我有一個(gè)小狗", "我有一個(gè)小狗我有一個(gè)小狗我有一個(gè)小狗我有一個(gè)小狗我有一個(gè)小狗"));
}
break;
}
}
}
4鞠评,對應(yīng)是實(shí)例中只增加了一個(gè)isShow參數(shù)來記錄狀態(tài)
package com.mumu.jsrecyclerview2;
import java.io.Serializable;
import java.util.List;
public class TestEntity implements Serializable {
/**
* Success : true
* StatusCode : 200
* Result : {"list":[{"TestTitle":"我愛小狗","TestNessage":"我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗"},{"TestTitle":"我愛小狗","TestNessage":"我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗"},{"TestTitle":"我愛小狗","TestNessage":"我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗"},{"TestTitle":"我愛小狗","TestNessage":"我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗"},{"TestTitle":"我愛小狗","TestNessage":"我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗"}]}
*/
private ResultBean Result;
public ResultBean getResult() {
return Result;
}
public void setResult(ResultBean Result) {
this.Result = Result;
}
public static class ResultBean {
private List<ListBean> list;
public List<ListBean> getList() {
return list;
}
public void setList(List<ListBean> list) {
this.list = list;
}
public static class ListBean {
/**
* TestTitle : 我愛小狗
* TestMessage : 我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗我愛小狗
* isShow: 是否顯示詳細(xì)消息茂蚓,后臺(tái)沒有返回,屬于自己添加賦值,用來記錄每一個(gè)item的顯示詳情狀態(tài)
*/
private String TestTitle;
private String TestMessage;
private boolean isShow = false;
public boolean isShow() {
return isShow;
}
public void setShow(boolean show) {
isShow = show;
}
public ListBean(String aaa, String bbb) {
TestTitle = aaa;
TestMessage = bbb;
}
public String getTestTitle() {
return TestTitle;
}
public void setTestTitle(String TestTitle) {
this.TestTitle = TestTitle;
}
public String getTestMessage() {
return TestMessage;
}
public void setTestMessage(String TestMessage) {
this.TestMessage = TestMessage;
}
}
}
}
5聋涨,對應(yīng)的適配器晾浴。適配器中根據(jù)對應(yīng)data中isShow參數(shù)顯示或者隱藏view,這還要多注意一點(diǎn)牍白,每個(gè)view都需要給他賦值脊凰,不然會(huì)發(fā)生數(shù)據(jù)沒有更新等不正常現(xiàn)象淹朋。
package com.mumu.jsrecyclerview2;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
public class TestAdapter extends BaseQuickAdapter<TestEntity.ResultBean.ListBean, BaseViewHolder> {
/**
* 增加一個(gè)構(gòu)造方法笙各,便于沒有數(shù)據(jù)時(shí)候初始化適配器
*/
public TestAdapter() {
super(R.layout.item_test);
}
/**
* 繼承BaseQuickAdapter后需要重寫的方法
*
* @param helper view持有者,為重用view而設(shè)計(jì)础芍,減少每次創(chuàng)建view的內(nèi)存消耗
* @param data 我們的列表數(shù)據(jù)
*/
@Override
protected void convert(BaseViewHolder helper, TestEntity.ResultBean.ListBean data) {
// TODO: 2019/1/10 需要詳細(xì)說明的點(diǎn):每一個(gè)子控件都要賦值操作杈抢,不然會(huì)造成數(shù)據(jù)混亂 ,如沒有給箭頭賦值仑性,在點(diǎn)擊
// TODO: 2019/1/10 展開隱藏的時(shí)候箭頭的賦值會(huì)發(fā)生錯(cuò)亂(點(diǎn)擊第一個(gè)惶楼,第十一個(gè)數(shù)據(jù)也會(huì)更改)
//將每一個(gè)需要賦值的id和對應(yīng)的數(shù)據(jù)綁定,綁定title和message
helper.setText(R.id.tv_item_title, data.getTestTitle())
.setText(R.id.tv_item_message, data.getTestMessage());
//設(shè)置箭頭切換
if(data.isShow()){
helper.setImageResource(R.id.iv_item_arrow, R.mipmap.rw_arrow_1);
}else {
helper.setImageResource(R.id.iv_item_arrow, R.mipmap.rw_arrow_2);
}
//設(shè)置詳細(xì)消息布局隱藏
helper.setGone(R.id.ll_item_message, data.isShow());
//設(shè)置title的點(diǎn)擊監(jiān)聽
helper.addOnClickListener(R.id.rl_item_title);
}
}
6诊杆,對應(yīng)的適配器的每個(gè)子布局文件歼捐。
<?xml version="1.0" encoding="utf-8"?>
<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="wrap_content"
android:background="#ffffff"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/rl_item_title"
android:layout_width="match_parent"
android:layout_height="48dp">
<TextView
android:id="@+id/tv_item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="16dp"
android:text="--"
android:textColor="#303030" />
<ImageView
android:id="@+id/iv_item_arrow"
android:layout_width="13.3dp"
android:layout_height="8dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:layout_marginRight="16dp"
android:src="@mipmap/rw_arrow_2" />
</RelativeLayout>
<LinearLayout
android:id="@+id/ll_item_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="15dp"
android:background="#EBEBEB" />
<TextView
android:id="@+id/tv_item_message"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center_vertical"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="--"
android:textColor="#999999"
android:textSize="14sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="12dp"
android:background="#F6F7F9" />
</LinearLayout>
7,對應(yīng)github地址
demo地址:https://github.com/mamumu/jsRecyclerView2
如果有發(fā)現(xiàn)錯(cuò)誤歡迎指正我及時(shí)修改晨汹,如果有好的建議歡迎留言豹储。如果覺得對你有幫助歡迎給小星星,謝謝淘这。