转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/125759325 本文出自【赵彦军的博客】
RecyclerView 基本使用
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/fruit_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.appcompat.widget.LinearLayoutCompat>
item_layout.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="200dp"
android:background="#ddd"
android:layout_marginTop="10dp"
android:orientation="vertical">
<TextView
android:id="@+id/fruit_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="30sp"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#aaffcc" />
</LinearLayout>
Fruit
public class Fruit {
private String fruitName;
public String getFruitName() {
return fruitName;
}
public Fruit(String fruitName) {
this.fruitName = fruitName;
}
public static List<Fruit> initFruitList() {
List<Fruit> fruitList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
Fruit apple = new Fruit("Item " + i);
fruitList.add(apple);
}
return fruitList;
}
}
FruitAdapter
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
private List<Fruit> mFruitList;
public FruitAdapter(List<Fruit> fruitList) {
mFruitList = fruitList;
}
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
Fruit fruit = mFruitList.get(position);
viewHolder.fruitName.setText(fruit.getFruitName());
}
@Override
public int getItemCount() {
return mFruitList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView fruitName;
public ViewHolder(@NonNull View itemView) {
super(itemView);
fruitName = itemView.findViewById(R.id.fruit_name);
}
}
@Override
public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
}
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
@Override
public void onViewAttachedToWindow(@NonNull ViewHolder holder) {
super.onViewAttachedToWindow(holder);
}
@Override
public void onViewDetachedFromWindow(@NonNull ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
}
}
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var adapter: FruitAdapter? = null
private var list = mutableListOf<Fruit>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
list = Fruit.initFruitList()
adapter = FruitAdapter(list)
binding.fruitRecyclerView.layoutManager = LinearLayoutManager(this)
binding.fruitRecyclerView.adapter = adapter
}
}
FruitAdapter
在上面,FruitAdapter 有四个方法
@Override
public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
}
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
@Override
public void onViewAttachedToWindow(@NonNull ViewHolder holder) {
super.onViewAttachedToWindow(holder);
}
@Override
public void onViewDetachedFromWindow(@NonNull ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
}
Adapter中的 onAttachedToRecyclerView
onAttachedToRecyclerView 、 onDetachedFromRecyclerView 这两个方法是对于 adapter 来说的,当 adapter 和 recyclerView 进行绑定的时候会回调 onAttachedToRecyclerView
什么时候会回调 onDetachedFromRecyclerView ?
答案:recyclerView 已经有 adapter 了,又绑定了一个新的 adapter ,就会执行 onDetachedFromRecyclerView
对于一个 adapter 实例,onAttachedToRecyclerView 、 onDetachedFromRecyclerView 这两个方法只会回调一次。
源码分析:
onAttachedToRecyclerView 、 onDetachedFromRecyclerView 在 RecyclerView 都是空方法。
首先看看 RecyclerView 的 setAdapter 方法
setAdapter 方法里,调用 setAdapterInternal 方法
设置一个新的 adapter , 如果 recyclerView 已经绑定过 adapter 。
那么就对于老的adapter 调用 onDetachedFromRecyclerView(this)
新的 adapter 调用 onAttachedToRecyclerView(this)
Adapter中的 onViewAttachedToWindow
@Override
public void onViewAttachedToWindow(@NonNull ViewHolder holder) {
super.onViewAttachedToWindow(holder);
int position = holder.getLayoutPosition();
Log.d("yu--", "attach " + position);
}
@Override
public void onViewDetachedFromWindow(@NonNull ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
int position = holder.getLayoutPosition();
Log.d("yu--", "detach " + position);
}
RecyclerView 本质上也是一个 ViewGroup ,那么它的 Item 要显示出来,自然需要 addView() 进来,移出的时候,当然也要 removeView() 出去,所以对应的自然是 onViewAttachedToWindow() 和 onViewAttachedToWindow() 了。
所以在特定场景下,可以通过这两个回调来解决少量 Item 移出屏幕,移进屏幕所需要的工作。为什么说特定场景下呢,由于假如调用了 notifyDataSetChanged() 方法的话,会触发当前在屏幕中的所有 Item 的 onViewAttachedToWindow() 。
当第一次 setAdapter 的时候,屏幕内所有 item 会调用 onViewAttachedToWindow(ViewHolder holder) , 日志如下:
yu--: attach 0
yu--: attach 1
yu--: attach 2
yu--: attach 3
yu--: attach 4
yu--: attach 5
yu--: attach 6
调用 notifyDataSetChanged ,屏幕类所有的 item 会先执行 onViewDetachedFromWindow , 然后执行 onViewAttachedToWindow
yu--: detach 6
yu--: detach 5
yu--: detach 4
yu--: detach 3
yu--: detach 2
yu--: detach 1
yu--: detach 0
yu--: attach 0
yu--: attach 1
yu--: attach 2
yu--: attach 3
yu--: attach 4
yu--: attach 5
yu--: attach 6
综上,Adapter 的 onViewAttachedToWindow 适合做 item 曝光埋点,但是要注意,这个方法可能会执行多次。
瀑布流 StaggeredGridLayoutManager 设置第一个 item 占据一整行
@Override
public void onViewAttachedToWindow(@NonNull ViewHolder holder) {
super.onViewAttachedToWindow(holder);
int position = holder.getLayoutPosition();
StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();
if (position == 0) {
layoutParams.setFullSpan(true);
} else {
layoutParams.setFullSpan(false);
}
}
效果图:
|