Fragment+RecyclerView實現吸頂式佈局+item點擊事件
在上次的微信Fragment項目基礎上,選擇一個tab實現用RecyclerView顯示內容。我實現的是吸頂式顯示外加點擊item會有Toast提示。
項目文件已上傳至github,詳見 1. layout文件 2. java文件
以下RecyclerView的效果實現參考https://www.jianshu.com/p/c4cfe38a91ed
修改build.gradle(Module:app)
我使用的Android Studio的版本是3.5.3,一開始按照v7的包使用RecyclerView出現很多編譯問題以及運行時閃退問題,網上查找原因,發現是此AS版本已經不支持使用v7了。
後查找到此解決方法,如下後三行(不包括註釋)代碼。
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
// implementation 'androidx.recyclerview:recyclerview:1.1.0'
def recyclerview_version = "1.0.0"
implementation "androidx.recyclerview:recyclerview:$recyclerview_version"
// For control over item selection of both touch and mouse driven selection
implementation "androidx.recyclerview:recyclerview-selection:$recyclerview_version"
}
編寫佈局xml文件
//tab_addr.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">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rcv_sticky"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"
android:scrollbars="none"/>
<include layout="@layout/sticky_item" />
</RelativeLayout>
//item.xml
//內容項item
<?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">
<include layout="@layout/sticky_item"/>
<TextView
android:id="@+id/txtPlants"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:textSize="20sp"
android:textColor="#666"
android:text="TextView" />
</LinearLayout>
// sticky_item.xml
//吸頂item
<?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">
<TextView
android:id="@+id/txtSunlight"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="25sp"
android:padding="3dp"
android:textColor="#666"
android:background="#DBEDFF"
android:text="TextView" />
</LinearLayout>
item.xml和RecyclerView所在的xml文件都要include一個吸頂item佈局(sticky_item.xml)。
編寫adapter
先寫好數據類GroupData.java,裏面有sunlight和plants,sunlight的數據是吸頂顯示的,plants的數據是內容項。
StickyAdapter.java
private Context mContext;
private List<GroupData> mList;
private OnItemClickListener mListener;
public static final int FIRST_STICKY_VIEW = 1;
public static final int HAS_STICKY_VIEW = 2;
public static final int NONE_STICKY_VIEW = 3;
public void onBindViewHolder(@NonNull StickyViewHolder holder, int position) {
final GroupData groupData = mList.get(position);
holder.txtPlants.setText(groupData.plants);
if (position == 0) {
holder.txtSunlight.setVisibility(View.VISIBLE);
holder.txtSunlight.setText(groupData.sunlight);
holder.itemView.setTag(FIRST_STICKY_VIEW);
} else {
if (!TextUtils.equals(groupData.sunlight, mList.get(position-1).sunlight)) {
holder.txtSunlight.setVisibility(View.VISIBLE);
holder.txtSunlight.setText(groupData.sunlight);
holder.itemView.setTag(HAS_STICKY_VIEW);
} else {
holder.txtSunlight.setVisibility(View.GONE);
holder.itemView.setTag(NONE_STICKY_VIEW);
}
}
holder.itemView.setContentDescription(groupData.sunlight);
//點擊事件傳入addrFragment(Activity)
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mListener.onItemClick(groupData.plants);
}
});
}
編寫Fragment
首先初始化數據:
private List<String> mList = new ArrayList<>();
private List<GroupData> mDataList = new ArrayList<>();
private void initList() {
mList.add("陽光:0|小噴菇");
mList.add("陽光:0|水兵菇");
mList.add("陽光:25|土豆地雷");
mList.add("陽光:25|陽光菇");
//更多mList.add...
}
private void initData() {
for (int i = 0; i < mList.size(); i++) {
GroupData groupData = new GroupData();
String s = mList.get(i);
String sunlight = s.substring(0, s.indexOf("|"));//得到mList前半邊的數據給sunlight
String plants = s.substring(s.indexOf("|") + 1);//得到mList後半邊的數據給plants
groupData.setSunlight(sunlight);
groupData.setPlants(plants);
mDataList.add(groupData);
}
}
然後是將數據顯示出來
private Context context;
private RecyclerView mRcv;
private StickyAdapter stickyAdapter;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.tab_addr, container, false);
context = view.getContext();
initList();
initData();
initView(view);
return view;
}
private void initView(View view) {
stickyAdapter = new StickyAdapter(context, this);
mRcv = view.findViewById(R.id.rcv_sticky);
final TextView txtSunlight = view.findViewById(R.id.txtSunlight);
LinearLayoutManager manager = new LinearLayoutManager(context);
manager.setOrientation(LinearLayoutManager.VERTICAL);
mRcv.setLayoutManager(manager);
mRcv.setHasFixedSize(true);
mRcv.setAdapter(stickyAdapter);
stickyAdapter.setStickyDataList(mDataList);
mRcv.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
View stickyView = recyclerView.findChildViewUnder(txtSunlight.getMeasuredWidth()/2, 5);
if (stickyView != null && stickyView.getContentDescription() != null) {
txtSunlight.setText(String.valueOf(stickyView.getContentDescription()));
}
View transInfoView = recyclerView.findChildViewUnder(txtSunlight.getMeasuredWidth()/2, txtSunlight.getMeasuredHeight()+1);
if (transInfoView != null && transInfoView.getTag() != null) {
int tranViewStatus = (int) transInfoView.getTag();
int dealtY = transInfoView.getTop() - txtSunlight.getMeasuredHeight();
if (tranViewStatus == StickyAdapter.HAS_STICKY_VIEW) {
if (transInfoView.getTop() > 0) {
txtSunlight.setTranslationY(dealtY);
} else {
txtSunlight.setTranslationY(0);
}
} else if (tranViewStatus == StickyAdapter.NONE_STICKY_VIEW) {
txtSunlight.setTranslationY(0);
}
}
}
});
}
點擊事件Toast提示
public void onItemClick(String content) {
Toast.makeText(context, "這是 " + content, Toast.LENGTH_SHORT).show();
}
實現吸頂效果時,因爲StickyAdapter.java中的onCreateViewHolder方法中本應該是 View view = LayoutInflater.from(mContext).inflate(R.layout.item, parent, false); 的代碼寫錯了目標佈局id,導致編譯時成功而運行時一點擊tab_addr按鈕區就閃退,AS的logcat報空指針的錯誤。
java.lang.NullPointerException: Attempt to invoke virtual method ‘void android.widget.TextView.setText(java.lang.CharSequence)’ on a null object reference
按我在網上查找到說法是項目它運行時遇到了找不到某個id的情況。
運行結果