需求:
实现Item在不同屏宽度上的数量自适应,以达到界面的保真。
实验过程:
设置了两个模拟器,将demo跑到不同的模拟器,以及横竖屏进行切换看具体的效果。
模拟器屏数据:
实验效果:
修改原理:
RecycleView的布局由LayoutManager完成,网格布局由StaggeredGridLayoutManager控制,同时在RecycleView绘制之前需要设置好每行显示的数量,于是可以在RecycleView整个绘制之前,对Item数量进行调整,同时需要对item的宽度大小进行控制。
具体代码如下:
main.xml说明:布局文件中最主要的是app:xc_auto_item_width属性的设置
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.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="match_parent"
tools:context=".MainActivity">
<com.rcl.recyclerviewdemo.widget.XCAutoRecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:xc_auto_item_flag="width_auto"
app:xc_auto_item_width="350dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
自定组件设置传递熟数据
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="XCAutoRecyclerView">
<attr name="xc_auto_item_flag">
<flag name="no_auto" value="0" />
<flag name="all_auto" value="1" />
<flag name="width_auto" value="2" />
<flag name="height_auto" value="3" />
</attr>
<attr name="xc_auto_item_width" format="dimension" />
<attr name="xc_auto_item_min_width" format="dimension" />
<attr name="xc_auto_item_max_width" format="dimension" />
</declare-styleable>
</resources>
具体组件自定义逻辑
public class XCAutoRecyclerView extends RecyclerView {
private static final String TAG = "XCAutoRecyclerView";
/**
* 不需要处理自适应,默认情况
*/
private static final int XC_AUTO_TYPE_NO = 0;
/**
* 宽高全部自适应
*/
private static final int XC_AUTO_TYPE_ALL = 1;
/**
* 宽度自适应
*/
private static final int XC_AUTO_TYPE_WIDTH = 2;
/**
* 高度自适应
*/
private static final int XC_AUTO_TYPE_HEIGHT = 3;
/**
* item的自适应模式
*/
private int xcAutoItemFlag = 0;
/**
* item自适应的宽度
*/
private int xcAutoItemWidth = 0;
/**
* item自适应的最小宽度
*/
private int xcAutoItemMinWidth = 0;
/**
* item自适应的最大宽度
*/
private float xcAutoItemMaxWidth = 0;
private Context xcContext;
public XCAutoRecyclerView(@NonNull Context context) {
super(context);
xcContext = context;
}
public XCAutoRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initParams(context, attrs);
}
public XCAutoRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initParams(context, attrs);
}
/**
* 获取xml中属性值
*/
private void initParams(Context context, AttributeSet attrs) {
xcContext = context;
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.XCAutoRecyclerView);
if (typedArray != null) {
xcAutoItemFlag = typedArray.getInt(R.styleable.XCAutoRecyclerView_xc_auto_item_flag, XC_AUTO_TYPE_NO);
xcAutoItemWidth = px2dp(typedArray.getDimension(R.styleable.XCAutoRecyclerView_xc_auto_item_width, 0));
xcAutoItemMinWidth = px2dp(typedArray.getDimension(R.styleable.XCAutoRecyclerView_xc_auto_item_min_width, 0));
xcAutoItemMaxWidth = px2dp(typedArray.getDimension(R.styleable.XCAutoRecyclerView_xc_auto_item_max_width, 0));
Log.i("jamie", "xcAutoItemFlag:" + xcAutoItemFlag + "---xcAutoItemWidth:" + xcAutoItemWidth + "---xcAutoItemMinWidth:" + xcAutoItemMinWidth + "---xcAutoItemMaxWidth:" + xcAutoItemMaxWidth);
typedArray.recycle();
}
}
/**
* 在测量前,更改对应配置
*/
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
LayoutManager xcLayout = getLayoutManager();
if (xcLayout != null && xcLayout instanceof StaggeredGridLayoutManager) {
StaggeredGridLayoutManager xcStaggeredGridLayoutManager = (StaggeredGridLayoutManager) xcLayout;
setLayoutManager(doAotoItemShow(xcStaggeredGridLayoutManager, widthSpec, heightSpec));
}
super.onMeasure(widthSpec, heightSpec);
}
/**
* 计算出显示数量,并进行更改
*/
private LayoutManager doAotoItemShow(StaggeredGridLayoutManager xcLayout, int widthSpec, int heightSpec) {
int width = LayoutManager.chooseSize(widthSpec, getPaddingLeft() + getPaddingRight(), ViewCompat.getMinimumWidth(this));
Log.i("jamie", "width:" + width);
if (xcAutoItemFlag == XC_AUTO_TYPE_ALL || xcAutoItemFlag == XC_AUTO_TYPE_WIDTH) {
int itemNumber = width / xcAutoItemWidth;
xcLayout.setSpanCount(itemNumber == 0 ? 1 : itemNumber);
}
return xcLayout;
}
/**
* 将px值转换为dp值
*/
public int px2dp(float pxValue) {
final float scale = xcContext.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
}