Recyclerview
基本使用
导包;
就一行代码,具体导入哪个版本自己看
设置布局控件
<androidx.recyclerview.widget.RecyclerVIew
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.recyclerview.widget.RecyclerVIew>
另外还需要对列表item里的显示内容进行单独的layout设置。
<androidx.constaintlayout.widget.ConstraintLayout
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="100dp"
tools:viewBindingIgnore="true">
<TextView
android:id="@+id/tvNumber"
android:layout_width="28dp"
android:layout_height="28dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginTop="3dp"
android:background="@drawable/search_default_medal"
android:scaleType="fitXY"
android:text="1"
android:textSize="13dp"
android:textColor="@color/white"
android:paddingTop="3dp"
android:gravity="center_horizontal"
/>
<ImageView
android:id="@+id/ivIcon"
android:layout_width="60dp"
android:layout_height="46dp"
app:layout_constraintLeft_toRightOf="@+id/tvNumber"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:laout_marginLeft="10dp"/>
<TextView
android:id="@+id/tvTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@+id/ivIcon"
app:layout_constraintleft_toRightOf="@+id/ivIcon"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:text=""
android:textSize="14dp"
android:textColor="@color/white"
android:lines="1"
android:ellipsize="end"
/>
<TextView
android:id="@+id/tvSource"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/ivIcon"
app:layout_constraintLeft_toLeftOf="@+id/tvTitle"
android:text="1"
android:textSize="14dp"
android:textColor="@color/white"
android:lines="1"
/>
<ImageView
android:id="@+id/ivLabel"
android:layout_width="35dp"
android:layout_height="17dp"
android:paddingLeft="3dp"
android:paddingRight="3dp"
android:scaleType="fitXY"
app:layout_constraintLeft_toRightOf="@+id/tvSource"
app:layout_constraintEnd_toStartOf="@+id/tvHotNumber"
app:layout_constraintBottom_toBottomOf="@+id/tvSource"
app:layout_constraintTop_toTopOf="@+id/tvSource"
/>
<TextView
android:id="@+id/tvHotNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/ivIcon"
app:layout_constraintRight_toRightOf="parent"
android:gravity="right"
android:text="1"
android:textSize="14dp"
android:textColor="@color/white"
android:lines="1"
/>
</androidx.constaintlayout.widget.ConstraintLayout>
设置item的数据类,添加adapter,设置item对应的类;
data class SearchHotBean{
var articleId:String?,
var jumpPage:String?,
var jumpUrl:String ?,
var hotValue:String?,
var title:String?,
var cover:String?,
var articleSourceName:String?,
var hotValueShowText:String?,
var searchLabelIconUrl:String?,
var bitmap:Bitmap?
}
定义adapter,其中里面包含了一个承载列表item布局的viewHolder
inner class ViewHolder(itemVIew:View):RecyclerView.ViewHolder(itemView){
val tvNumber: TextView by lazy{itemView.findViewById<TextView>(R.id.tvNumber)}
val ivIcon: ImageView by lazy{itemView.findViewById<ImageView>(R.id.ivIcon)}
val tvTitle: TextView by lazy{itemView.findViewById<TextView>(R.id.tvTitle)}
val tvSource: TextView by lazy{itemView.findViewById<TextView>(R.id.tvSource)}
val ivLabel: ImageView by lazy{itemView.findViewById<ImageView>(R.id.ivLabel)}
val tvHotNumber: TextView by lazy{itemView.findViewById<TextView>(R.id.tvHotNumber)}
}
接下来就是adapter类
class ListAdapter(private val list : List<SearchHotBean>,var context:Context):RecyclerView.Adapter<ListAdapter.ViewHolder>(){
override fun onCreateViewHolder(patent: ViewGroup,viewType: Int): ViewHolder{
val view=LayoutInflater.from(parent.context).inflate(R.layout.search_test_item,parent,false)
retrun ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder,position: Int){
//具体操作不写了,主要是对列表各项item赋值
}
override fun getItemCount(): Int=list.size
inner class ViewHolder(itemView: View) RecyclerView.ViewHolder(itemView){
val tvNumber: TextView by lazy{itemView.findViewById<TextView>(R.id.tvNumber)}
val ivIcon: ImageView by lazy{itemView.findViewById<ImageView>(R.id.ivIcon)}
val tvTitle: TextView by lazy{itemView.findViewById<TextView>(R.id.tvTitle)}
val tvSource: TextView by lazy{itemView.findViewById<TextView>(R.id.tvSource)}
val ivLabel: ImageView by lazy{itemView.findViewById<ImageView>(R.id.ivLabel)}
val tvHotNumber: TextView by lazy{itemView.findViewById<TextView>(R.id.tvHotNumber)}
}
}
设置recyclerView控件的adapter和layoutmanager。
//在使用前定义adapter和layoutmanager即可。这里的binding.recyclerView主要是使用了ViewBinding的视图绑定方式
var conManager=LinearLayoutManager(this)
binding.recyclerView.layoutManager=conManager
fun setAdapter(){
val adapter=HotListAdapter(dataArray,context=this.getContext())
binding.recycleView.adapter=adapter
}
RecyclerView相关
LayoutManager布局管理器
LinearLayoutManager线性布局管理器,
共有三种构造方法
第一种构造方法
内部调用了第二种构造方法,
public LinearLayoutManager(Context context){
this(context,RecyclerView.DEFAULT_ORIENTATION,false);
}
第二种构造方法
/**
*context 上下文,初始化时,构造方法内部加载资源
*orientation 方向,默认为垂直,
*reverseLayout 是否倒序,true时从最后一个item开始倒序加载,false相反。整体依靠下方,意思是当列表项总数高度小于屏幕展示高度且为铺满控件的高度,则显示在控件布局的下方。
*/
public LinearLayoutManager(Context context,@RecyclerView.Orientation int orientation,boolean reverseLayout){
setOrientation(orientation);
setReverseLayout(reverseLayout);
}
第三种构造方法
使用的频率不多,主要是自定义属性的使用,根据优先级选择在不同的时机,根据需求来使用不同的样式。这部分只是稍微看了下自定义View构造函数这篇博客,以后如果实际中运用到时再去复习!!
/**
*attrs 属性值的合集,
*defStyleAttr 这是当前Theme中的包含的一个指向style的引用.当我们没有给自定义View设置declare-styleable资源集合时,默认从这个集合里面查找布局文件中配置属性值.传入0表示不向该defStyleAttr中查找默认值.
*defStyleRes 这个也是一个指向Style的资源ID,但是仅在defStyleAttr为0或者defStyleAttr不为0但Theme中没有为defStyleAttr属性赋值时起作用.
*/
public LinearLayoutManager(Context context,AttributeSet attrs,int defStyleAttr,int defStyleRes){
Properties properties=getProperties(context,attrs,defStyleAttr,defStyleRes);
setOrientation(properties.orientation);
setReverseLayout(properties.reverseLayout);
//When stack from bottom is set to true, the list fills its content starting from the bottom of the view.
//设置为true时,RecycelrView会自动滑倒尾部,直到最后一条数据完整展示,不会影响内部的顺序,默认展示末尾的item
setStackFromEnd(properties.stackFromEnd);
}
StaggeredGridLayoutManager错列网格布局管理器
第一种
//两个属性也不赘述
public StaggeredGridLayoutManager(int spanCount,int orientation){
mOrientation=orientation;
setSpanCount(spanCount);
mLayoutState=new LayoutState();
createOrientationHelpers();
}
第二种
public StaggeredGridLayoutManager(Context context,AttributeSet attrs,int defStyleAttr,int defStyleRes){
Properties properties=getProperties(context,attrs,defStyleAttr,defStyleRes);
setOrientation(properties.orientation);
setSpanCount(properties.spanCount);
setReverseLayout(properties.reverseLayout);
mLayoutState=new LayoutState();
createOrientationHelpers();
}
GridLayoutManager网格布局管理器
前两种布局管理器的综合,结合了LinearLayoutManager的反转和StaggeredGridLayoutManager的多列特点。也有三种构造方法
第一种
/**
*context ...不赘述
*spanCount ,默认为垂直时显示列数
*/
public GridLayoutManager(Context context,int spanCount){
super(context);
setSaanCount(spanCount);
}
第二种
/*
*context
*spanCount 列数
*orientation 方向
*reverseLayout 是否反转
*/
public GridLayoutManager(Context context,int spanCount,@RecyclerView.orientation int orientation,boolean reverseLayout){
super(context,orientation,reverseLayout);
setSpanCount(spanCount);
}
第三种
自定义属性,也不赘述
public GridLayoutManager(Context context,AttributeSet attrs,int defStyleAttr,int defStyleRes){
super(context,attrs,defStyleAttr,defStyleRes);
Properties properties=getProperties(context,attrs,defStyleAttr,defStyleRes);
setSpanCount(properties.spanCount);
}
Adapter类相关
RecyclerView.Adapter<HotListAdapter.ViewHolder>
重写方法onCreateViewHolder,onBindVIewHolder,getItemCount
//ViewHolder是自定义的内部类,用于绑定对应item的XML布局的各种控件
override fun onCreateViewHolder(parent:ViewGroup,viewTyper:Int):ViewHolder{
val view=LayoutInflater.from(parent.context).inflate(R.layout.xxx,parent,false)
return ViewHolder(view)
}
inflate详解
这里仔细看一下这行代码
//from是获得实例的方法。
val view=LayoutInflater.from(parent.context).inflate(R.layout.xxx,parent,false)
其中的inflate方法当时在设计出iten表项后,各个构造方法对item展示有很大的差异,所以也单独拿出来分析源码
public View inflate(@LayoutRes int resource,@Nullable ViewGroup root){
return inflate(resource,root,root≠null);
}
public View inflate(XmlPullParser parser,@Nullable ViewGroup root){
return inflate(parser,root,root≠null);
}
/**
*直接看第三个方法
*resource 想要添加的布局
*root 想要添加的布局的父布局
*attachToRoot 是否直接添加到第二个参数的布局上面,true表示layout文件填充的View直接添加到parent,false表示创建的view会以其他方式添加进parent
*/
public View inflate(@LayoutRes int resource,@Nullable ViewGroup root,boolean attachToRoot){
final Resources res=getContext().getResources();
if(DEBUG){
Log.d(TAG,"INFLATING from resource:\""+res.getResourceName(resource)+"\"("+Integer.toHexString(resource)+")");
}
View view=tryInflatePrecompiled(resource,res,root,attachRoot);
if(view≠null){
return view;
}
XmlResourceParser parser=res.getLayout(resource);
try{
return inflate(parser,root,attachToRoot);
}finally{
parser.close();
}
}