使用 GridLayoutManager 和 RecyclerView 更改列数
Changing number of columns with GridLayoutManager and RecyclerView
在我的片段中,我按以下方式设置我的 GridLayout:
mRecycler.setLayoutManager(new GridLayoutManager(rootView.getContext(), 2));
所以,我只想在用户旋转 phone/tablet 时将 2
更改为 4
。我已经阅读了有关 onConfigurationChanged
的信息,并且我试图让它适用于我的情况,但它没有以正确的方式进行。当我旋转 phone 时,应用程序崩溃了...
你能告诉我如何解决这个问题吗?
这是我找到解决方案的方法,但无法正常工作:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
int orientation = newConfig.orientation;
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
mRecycler.setLayoutManager(new GridLayoutManager(mContext, 2));
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
mRecycler.setLayoutManager(new GridLayoutManager(mContext, 4));
}
}
提前致谢!
尝试在您的 onCreateView 方法中处理它,因为每次方向改变时都会调用它:
if(getActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
mRecycler.setLayoutManager(new GridLayoutManager(mContext, 2));
}
else{
mRecycler.setLayoutManager(new GridLayoutManager(mContext, 4));
}
如果您有多个条件或在多个地方使用该值,这可能会很快失控。我建议创建以下结构:
res
- values
- dimens.xml
- values-land
- dimens.xml
其中 res/values/dimens.xml
为:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="gallery_columns">2</integer>
</resources>
和res/values-land/dimens.xml
是:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="gallery_columns">4</integer>
</resources>
然后代码变成(并永远保持)如下:
final int columns = getResources().getInteger(R.integer.gallery_columns);
mRecycler.setLayoutManager(new GridLayoutManager(mContext, columns));
您可以轻松地看到添加确定列数的新方法是多么容易,例如使用 -w500dp
/-w600dp
/-w700dp
资源文件夹而不是 -land
.
将这些文件夹分组到单独的资源文件夹中也很容易,以防您不想弄乱其他(更相关的)资源:
android {
sourceSets.main.res.srcDir 'src/main/res-overrides' // add alongside src/main/res
}
回收视图支持 AutofitRecycleView。
您需要在 xml 文件中添加 android:numColumns="auto_fit"
。
可以参考这个AutofitRecycleViewLink
您可以在您的recyclerView onMeasure 中实现该方法。
首先,创建 java class AutofitRecyclerView
public class AutofitRecyclerView extends RecyclerView {
//private GridLayoutManager manager;
private StaggeredGridLayoutManager manager;
private int columnWidth = -1;
public AutofitRecyclerView(Context context) {
super(context);
init(context, null);
}
public AutofitRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public AutofitRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
if (attrs != null) {
int[] attrsArray = {
android.R.attr.columnWidth
};
TypedArray array = context.obtainStyledAttributes(attrs, attrsArray);
columnWidth = array.getDimensionPixelSize(0, -1);
array.recycle();
}
manager = new StaggeredGridLayoutManager(1, GridLayoutManager.VERTICAL);
setLayoutManager(manager);
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
super.onMeasure(widthSpec, heightSpec);
if (columnWidth > 0) {
int spanCount = Math.max(1, getMeasuredWidth() / columnWidth);
manager.setSpanCount(spanCount);
}
}}
在你的 xlm 布局文件中 activity_main.xml
<yourpackagename.AutofitRecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="@dimen/column_width"
android:clipToPadding="false"/>
然后将变量设置为values文件夹values/dimens的文件大小中每一项的宽度values/dimens。xml
<resources>
<dimen name="column_width">250dp</dimen>
</resources>
可以针对不同的屏幕分辨率values-xxhdpi/dimens。xml
<resources>
<dimen name="column_width">280dp</dimen>
</resources>
在您的 activity onCreate 事件中放置以下代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.addItemDecoration(new MarginDecoration(this));
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(new NumberedAdapter(50));
}
在onCreate()事件中可以使用StaggeredGridLayoutManager
mRecyclerView = (RecyclerView) v.findViewById(R.id.recyclerView);
mStaggeredGridLayoutManager = new StaggeredGridLayoutManager(
1, //number of grid columns
GridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(mStaggeredGridLayoutManager);
然后当用户旋转屏幕时捕获事件,并自动更改列数
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (getActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
mStaggeredGridLayoutManager.setSpanCount(1);
} else {
//show in two columns
mStaggeredGridLayoutManager.setSpanCount(2);
}
}
一种更可靠的方法来确定号码。列数将根据屏幕宽度和运行时进行计算。我通常为此使用以下功能。
public static int calculateNoOfColumns(Context context) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
float dpWidth = displayMetrics.widthPixels / displayMetrics.density;
int scalingFactor = 200; // You can vary the value held by the scalingFactor
// variable. The smaller it is the more no. of columns you can display, and the
// larger the value the less no. of columns will be calculated. It is the scaling
// factor to tweak to your needs.
int columnCount = (int) (dpWidth / scalingFactor);
return (columnCount>=2?columnCount:2); // if column no. is less than 2, we still display 2 columns
}
这是一种更动态的方法来准确计算号码。的列。这将更适合不同屏幕尺寸的用户,而不会仅限于两个可能的值。
注意: 您可以改变 scalingFactor 变量持有的值。越小越没有。您可以显示的列的数量,值越大,数量越少。将计算列数。它是根据您的需要进行调整的比例因子。
我最终在 onCreate 方法中处理了这个问题。
private RecyclerView recyclerView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
Configuration orientation = new Configuration();
if(this.recyclerView.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
} else if (this.recyclerView.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
recyclerView.setLayoutManager(new GridLayoutManager(this, 4));
}
connectGetApiData();
}
它非常适合我的应用程序。
除了答案。也可以仅使用 XML 属性来完成。下面是代码。
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/pax_seat_map_rv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:spanCount="3"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" />
我会试着一步一步解释。你可以查看我分享的integers.xml、integers.xml(土地)和github项目的MainFragment文件。您会看到列数会根据方向或屏幕尺寸而变化(平板电脑 vs phone)(我只会解释方向改变时如何操作,因为问题只是关于它)。
https://github.com/b-basoglu/NewsApp/blob/master/app/src/main/java/com/news/newsapp/ui/main/MainFragment.kt
创建一个名为 integers.xml 的资源文件。 -> 在项目 > Android 窗格中打开 res 文件夹,在值文件夹中 right-click,然后 select 新建 > 值资源文件。
将文件命名为 integers.xml 并单击“确定”。
在名为 grid_column_count 的标签之间创建一个整数常量并将其设置为等于 2:
<整数名称="grid_column_count">2整数>
创建另一个值资源文件,再次调用 integers.xml;但是,当您从可用限定符窗格中添加资源限定符时,该名称将被修改。资源限定符用于标记各种情况下的资源配置。
Select 在可用限定符窗格中定位,然后按对话框中间的 >> 符号来分配此限定符。
将屏幕方向菜单更改为横向,并注意目录名称 values-land 的显示方式。这是资源限定符的本质:目录名称告诉 Android 何时使用该特定布局文件。在这种情况下,即 phone 旋转到横向模式时。
点击确定生成新的布局文件。
将您创建的整数常量复制到这个新资源文件中,但将值更改为 4。
<整数名称="grid_column_count">4整数>
[你有这些文件][1]
- 现在您所要做的就是re-assigning配置更改时的跨度计数如下:
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
gridLayoutManager?.let {
it.spanCount = resources.getInteger(R.integer.grid_column_count)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
gridLayoutManager = GridLayoutManager(requireContext(),
resources.getInteger(R.integer.grid_column_count))
${yourRecyclerView}.layoutManager = gridLayoutManager
...
[1]: https://i.stack.imgur.com/3NZdq.png
在我的片段中,我按以下方式设置我的 GridLayout:
mRecycler.setLayoutManager(new GridLayoutManager(rootView.getContext(), 2));
所以,我只想在用户旋转 phone/tablet 时将 2
更改为 4
。我已经阅读了有关 onConfigurationChanged
的信息,并且我试图让它适用于我的情况,但它没有以正确的方式进行。当我旋转 phone 时,应用程序崩溃了...
你能告诉我如何解决这个问题吗?
这是我找到解决方案的方法,但无法正常工作:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
int orientation = newConfig.orientation;
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
mRecycler.setLayoutManager(new GridLayoutManager(mContext, 2));
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
mRecycler.setLayoutManager(new GridLayoutManager(mContext, 4));
}
}
提前致谢!
尝试在您的 onCreateView 方法中处理它,因为每次方向改变时都会调用它:
if(getActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
mRecycler.setLayoutManager(new GridLayoutManager(mContext, 2));
}
else{
mRecycler.setLayoutManager(new GridLayoutManager(mContext, 4));
}
如果您有多个条件或在多个地方使用该值,这可能会很快失控。我建议创建以下结构:
res
- values
- dimens.xml
- values-land
- dimens.xml
其中 res/values/dimens.xml
为:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="gallery_columns">2</integer>
</resources>
和res/values-land/dimens.xml
是:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="gallery_columns">4</integer>
</resources>
然后代码变成(并永远保持)如下:
final int columns = getResources().getInteger(R.integer.gallery_columns);
mRecycler.setLayoutManager(new GridLayoutManager(mContext, columns));
您可以轻松地看到添加确定列数的新方法是多么容易,例如使用 -w500dp
/-w600dp
/-w700dp
资源文件夹而不是 -land
.
将这些文件夹分组到单独的资源文件夹中也很容易,以防您不想弄乱其他(更相关的)资源:
android {
sourceSets.main.res.srcDir 'src/main/res-overrides' // add alongside src/main/res
}
回收视图支持 AutofitRecycleView。
您需要在 xml 文件中添加 android:numColumns="auto_fit"
。
可以参考这个AutofitRecycleViewLink
您可以在您的recyclerView onMeasure 中实现该方法。 首先,创建 java class AutofitRecyclerView
public class AutofitRecyclerView extends RecyclerView {
//private GridLayoutManager manager;
private StaggeredGridLayoutManager manager;
private int columnWidth = -1;
public AutofitRecyclerView(Context context) {
super(context);
init(context, null);
}
public AutofitRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public AutofitRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
if (attrs != null) {
int[] attrsArray = {
android.R.attr.columnWidth
};
TypedArray array = context.obtainStyledAttributes(attrs, attrsArray);
columnWidth = array.getDimensionPixelSize(0, -1);
array.recycle();
}
manager = new StaggeredGridLayoutManager(1, GridLayoutManager.VERTICAL);
setLayoutManager(manager);
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
super.onMeasure(widthSpec, heightSpec);
if (columnWidth > 0) {
int spanCount = Math.max(1, getMeasuredWidth() / columnWidth);
manager.setSpanCount(spanCount);
}
}}
在你的 xlm 布局文件中 activity_main.xml
<yourpackagename.AutofitRecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="@dimen/column_width"
android:clipToPadding="false"/>
然后将变量设置为values文件夹values/dimens的文件大小中每一项的宽度values/dimens。xml
<resources>
<dimen name="column_width">250dp</dimen>
</resources>
可以针对不同的屏幕分辨率values-xxhdpi/dimens。xml
<resources>
<dimen name="column_width">280dp</dimen>
</resources>
在您的 activity onCreate 事件中放置以下代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.addItemDecoration(new MarginDecoration(this));
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(new NumberedAdapter(50));
}
在onCreate()事件中可以使用StaggeredGridLayoutManager
mRecyclerView = (RecyclerView) v.findViewById(R.id.recyclerView);
mStaggeredGridLayoutManager = new StaggeredGridLayoutManager(
1, //number of grid columns
GridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(mStaggeredGridLayoutManager);
然后当用户旋转屏幕时捕获事件,并自动更改列数
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (getActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
mStaggeredGridLayoutManager.setSpanCount(1);
} else {
//show in two columns
mStaggeredGridLayoutManager.setSpanCount(2);
}
}
一种更可靠的方法来确定号码。列数将根据屏幕宽度和运行时进行计算。我通常为此使用以下功能。
public static int calculateNoOfColumns(Context context) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
float dpWidth = displayMetrics.widthPixels / displayMetrics.density;
int scalingFactor = 200; // You can vary the value held by the scalingFactor
// variable. The smaller it is the more no. of columns you can display, and the
// larger the value the less no. of columns will be calculated. It is the scaling
// factor to tweak to your needs.
int columnCount = (int) (dpWidth / scalingFactor);
return (columnCount>=2?columnCount:2); // if column no. is less than 2, we still display 2 columns
}
这是一种更动态的方法来准确计算号码。的列。这将更适合不同屏幕尺寸的用户,而不会仅限于两个可能的值。
注意: 您可以改变 scalingFactor 变量持有的值。越小越没有。您可以显示的列的数量,值越大,数量越少。将计算列数。它是根据您的需要进行调整的比例因子。
我最终在 onCreate 方法中处理了这个问题。
private RecyclerView recyclerView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
Configuration orientation = new Configuration();
if(this.recyclerView.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
} else if (this.recyclerView.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
recyclerView.setLayoutManager(new GridLayoutManager(this, 4));
}
connectGetApiData();
}
它非常适合我的应用程序。
除了答案。也可以仅使用 XML 属性来完成。下面是代码。
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/pax_seat_map_rv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:spanCount="3"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" />
我会试着一步一步解释。你可以查看我分享的integers.xml、integers.xml(土地)和github项目的MainFragment文件。您会看到列数会根据方向或屏幕尺寸而变化(平板电脑 vs phone)(我只会解释方向改变时如何操作,因为问题只是关于它)。 https://github.com/b-basoglu/NewsApp/blob/master/app/src/main/java/com/news/newsapp/ui/main/MainFragment.kt
创建一个名为 integers.xml 的资源文件。 -> 在项目 > Android 窗格中打开 res 文件夹,在值文件夹中 right-click,然后 select 新建 > 值资源文件。
将文件命名为 integers.xml 并单击“确定”。
在名为 grid_column_count 的标签之间创建一个整数常量并将其设置为等于 2:
<整数名称="grid_column_count">2整数>
创建另一个值资源文件,再次调用 integers.xml;但是,当您从可用限定符窗格中添加资源限定符时,该名称将被修改。资源限定符用于标记各种情况下的资源配置。
Select 在可用限定符窗格中定位,然后按对话框中间的 >> 符号来分配此限定符。
将屏幕方向菜单更改为横向,并注意目录名称 values-land 的显示方式。这是资源限定符的本质:目录名称告诉 Android 何时使用该特定布局文件。在这种情况下,即 phone 旋转到横向模式时。
点击确定生成新的布局文件。
将您创建的整数常量复制到这个新资源文件中,但将值更改为 4。
<整数名称="grid_column_count">4整数>
[你有这些文件][1]
- 现在您所要做的就是re-assigning配置更改时的跨度计数如下:
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
gridLayoutManager?.let {
it.spanCount = resources.getInteger(R.integer.grid_column_count)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
gridLayoutManager = GridLayoutManager(requireContext(),
resources.getInteger(R.integer.grid_column_count))
${yourRecyclerView}.layoutManager = gridLayoutManager
...
[1]: https://i.stack.imgur.com/3NZdq.png