具有动态项目高度的水平 RecyclerView
Horizontal RecyclerView with dynamic item’s Height
我正在尝试实现水平滚动的 RecyclerView
,所以我使用的是水平方向的 LinearLayoutManager
。问题是我使用 2 种不同类型的高度不同的项目填充 RecyclerView。这是我为项目使用的布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp">
<LinearLayout
android:id="@+id/document_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/ic_rounded"
android:backgroundTint="@color/ms_black_ms_gray"
android:gravity="center"
android:layout_gravity="bottom"
android:padding="5dp"
android:paddingStart="15dp">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="13sp"
android:singleLine="true"
android:maxWidth="80dp"
tools:text="example_form"/>
<TextView
android:id="@+id/format"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="13sp" />
…
</LinearLayout>
<android.support.v7.widget.CardView
android:id="@+id/image_view"
android:layout_width="120dp"
android:layout_height="80dp"
android:layout_gravity="bottom"
app:cardCornerRadius="25dp"
app:cardElevation="0dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/preview_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"/>
…
</RelativeLayout>
</android.support.v7.widget.CardView>
这是包含RecyclerView
的布局,基本上是这样的:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="14dp"
android:paddingEnd="14dp">
<ImageView
android:id="@+id/attach"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_gravity="bottom"
android:layout_marginBottom="19dp"
android:visibility="visible"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginBottom="10dp"
android:layout_marginTop="5dp"
android:padding="3dp"
android:foreground="@drawable/ic_rounded_stroke"
android:foregroundTint="@color/white">
<android.support.constraint.ConstraintLayout
android:id="@+id/chatEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ic_rounded"
android:foreground="@drawable/ic_rounded_stroke"
android:padding="6dp"
android:visibility="visible">
<EditText
android:id="@+id/editText"
android:textSize="17sp"
android:textColor="#121212"
android:letterSpacing="-0.02"
android:lineSpacingExtra="0sp"
android:padding="10dp"
android:paddingStart="15dp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="5"
android:hint="@string/chat_hint"
android:inputType="textCapSentences|textMultiLine"
android:maxLength="2500"
android:background="@null"
app:layout_constraintRight_toLeftOf="@id/buttonsContainer"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/send"
android:layout_gravity="bottom"
android:visibility="visible"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingBottom="10dp"
android:paddingTop="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="#ffffff"
android:letterSpacing="-0.02"
android:gravity="center_horizontal"
android:text="@string/send"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
<android.support.v7.widget.RecyclerView
android:id="@+id/filesList"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:paddingTop="5dp"
android:paddingEnd="5dp"
android:visibility="gone"
app:layout_constraintRight_toLeftOf="@id/send"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/editText"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>
</LinearLayout>
</LinearLayout>
我使用的是单个 ViewHolder
,我只是更改了 2 个子视图的可见性。
我期望得到的结果是这个:
但我得到的是这个; CardView 被切成两半,使用第二种类型的项目的高度:
我看到了,和我的问题类似。它建议使用 Google’s Flexbox
。所以,我尝试实现 FlexboxLayoutManager
:
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(getContext());
layoutManager.setFlexDirection(FlexDirection.ROW);
layoutManager.setFlexWrap(FlexWrap.NOWRAP);
我正在使用 row
方向,如果它不适合单行,它会在下一行显示项目。所以,我也加了No_wrap
。现在它在一行中显示项目但不提供滚动。同样在这种情况下,它会尝试通过减小项目的宽度来将所有项目放在一行中。
我也玩过 flex box 示例应用程序,但是我得不到我想要的结果。
有没有什么办法可以通过集成RecyclerView的Flexbox来实现水平滚动?或者我应该使用不同的方法?
谢谢
编辑
感谢您的提示和一切,但它并没有解决它。因此,我将代码精简到最低限度以重现这一点。
主要活动:
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CODE = 1;
private RecyclerView recyclerView;
private FilesAdapter filesAdapter;
private List<File> filesList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerView);
LinearLayoutManager filesLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(filesLayoutManager);
filesAdapter = new FilesAdapter(filesList);
recyclerView.setAdapter(filesAdapter);
ImageView attach = findViewById(R.id.attach);
attach.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(Intent.createChooser(intent,"Select Files"), REQUEST_CODE);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
try {
if (data != null) {
List<File> uriList = new ArrayList<>();
if (data.getClipData() != null) { // Multiple files
for (int i = 0; i < data.getClipData().getItemCount(); i++) {
Uri uri = data.getClipData().getItemAt(i).getUri();
Pair<Boolean, File> isValid = isFileValid(uri);
if (isValid.first) {
uriList.add(isValid.second);
}
}
} else { // Single file
Uri uri = data.getData();
Pair<Boolean, File> isValid = isFileValid(uri);
if (isValid.first) {
uriList.add(isValid.second);
}
}
if (uriList.size() > 0) {
for (File file : uriList) {
filesList.add(filesList.size(), file);
filesAdapter.notifyItemInserted(filesList.size());
}
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
super.onActivityResult(requestCode, resultCode, data);
}
private Pair<Boolean, File> isFileValid(Uri uri) throws NullPointerException {
Pair<Boolean, File> defaultResponse = Pair.create(false, null);
Cursor c = getContentResolver().query(uri, null, null, null, null);
if (c != null) {
c.moveToFirst();
String filename = c.getString(c.getColumnIndex(OpenableColumns.DISPLAY_NAME));
if (isSupported(filename)) {
c.close();
return Pair.create(true, new File(StringUtils.endsWithIgnoreCase(filename, ".pdf") ? DOCUMENT : IMAGE));
} else {
Toast.makeText(this, "File format not supported", Toast.LENGTH_SHORT).show();
c.close();
return defaultResponse;
}
}
return defaultResponse;
}
private boolean isSupported(String filename) {
String[] supportedFormats = { ".pdf", ".jpg", ".gif", ".png" };
for (String format : supportedFormats) {
if (StringUtils.endsWithIgnoreCase(filename, format)) {
return true;
}
}
return false;
}
}
主要activity布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/attach"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_marginBottom="19dp"
android:padding="10dp"
android:src="@drawable/ic_attach" />
</LinearLayout>
文件:
public class File {
public enum Type {
DOCUMENT,
IMAGE
}
private Type type;
public File(Type type) {
this.type = type;
}
public Type getType() {
return type;
}
}
文件适配器:
public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.BaseViewHolder> {
private List<File> files;
public FilesAdapter(List<File> files) {
this.files = files;
}
@NonNull
@Override
public FilesAdapter.BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(viewType == 0 ? R.layout.document_item : R.layout.image_item, parent, false);
if (viewType == 0) {
return new DocumentViewHolder(view);
} else {
return new ImageViewHolder(view);
}
}
@Override
public void onBindViewHolder(@NonNull FilesAdapter.BaseViewHolder viewHolder, int position) {
viewHolder.bind(files.get(position));
}
@Override
public int getItemViewType(int position) {
if (files.get(position).getType() == File.Type.DOCUMENT) {
return 0;
} else {
return 1;
}
}
@Override
public int getItemCount() {
return files.size();
}
abstract static class BaseViewHolder extends RecyclerView.ViewHolder {
public BaseViewHolder(@NonNull View itemView) {
super(itemView);
}
abstract void bind(File file);
}
static class ImageViewHolder extends BaseViewHolder {
public ImageViewHolder(@NonNull View itemView) {
super(itemView);
}
@Override
void bind(File file) { }
}
static class DocumentViewHolder extends BaseViewHolder {
public DocumentViewHolder(@NonNull View itemView) {
super(itemView);
}
public void bind(File file) { }
}
}
文档项:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="150dp"
android:layout_height="40dp"
android:background="@drawable/ic_rounded"
android:backgroundTint="#888888"
android:layout_margin="5dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="PDF"
android:textColor="@android:color/white"/>
</LinearLayout>
图片项:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="120dp"
android:layout_height="80dp"
android:layout_margin="5dp"
app:cardBackgroundColor="#000000"
app:cardCornerRadius="10dp"
app:cardElevation="0dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="IMAGE"
android:textColor="@android:color/white"/>
</androidx.cardview.widget.CardView>
如果我先 select 一个图像,然后是几个 pdf,它工作正常:
但如果我先 select 3 个 pdf,然后是图像,就会发生这种情况:
知道如何解决这个问题吗?
为你的 RecyclerView 试试这个:
android:layout_height="wrap_content"
因为包含你的 RecyclerView 的 XML 文件在这里不完整我不能确定但是如果你的 RecyclerView 在另一个限制它的父视图中,那么我想使用 wrap_content 作为RecyclerView 的高度加上一些调整应该可以解决它。
另外,请注意,您将 RecyclerView 限制在顶部“editText”的底部,这样可能会阻止您的 RecyclerView 扩展。
首先,我认为您的主要布局有点过于复杂。您可以在单个 ConstraintLayout
中完成所有操作(如果您需要围绕特定项目设置框架背景,我建议使用使用 Barrier
和 Guideline
布置的纯 View
实例s - 参见 https://medium.com/better-programming/essential-components-of-constraintlayout-7f4026a1eb87)
另一个 and/or 改进是不使用 right/left 约束,而是 start/end。这也为 RTL 显示准备了布局。
此外,我强烈建议对 RecyclerView
中的不同项目使用单独的布局文件和 ViewHolder
s。
正如其他人在评论中指出的那样,您的 RecyclerView
是使用 match_parent
布局的,这反过来又可以裁剪您的视图。您可能需要设置此 wrap_content
.
与此同时,您可能还想更新依赖项以使用 Android Jetpack 并放弃支持库。
您所要做的就是将 recyclerview 高度设置为最大项目的高度,在您的例子中是图像项目。
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="wrap_content"
android:layout_height="80dp" />
我在另一个项目中遇到了类似的问题,我使用 Google 库 FlexboxLayoutManager 解决了它。
- 获取最新的 FlexboxLayoutManager 库 (https://github.com/google/flexbox-layout) 并将其添加到您的 grandle 依赖项中(实现 'com.google.android:flexbox:2.0.1')
- 在您的 Activity 中添加以下代码行:
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(this);
layoutManager.setFlexDirection(FlexDirection.ROW);
layoutManager.setFlexWrap(FlexWrap.NOWRAP);
recyclerView.setLayoutManager(layoutManager);
- 要使 FlexboxLayoutManager 与水平滚动一起工作,请在 BaseViewHolder class 的适配器 (FilesAdapter) 中添加以下代码:
abstract static class BaseViewHolder extends RecyclerView.ViewHolder {
public BaseViewHolder(@NonNull View itemView) {
super(itemView);
ViewGroup.LayoutParams lp = itemView.getLayoutParams();
if (lp instanceof FlexboxLayoutManager.LayoutParams) {
FlexboxLayoutManager.LayoutParams flexboxLp = (FlexboxLayoutManager.LayoutParams) lp;
flexboxLp.setFlexShrink(0.0f);
flexboxLp.setAlignSelf(AlignItems.FLEX_START); //this will align each itemView on Top or use AlignItems.FLEX_END to align it at Bottom
}
}
abstract void bind(File file);
}
首先选择 pdf 文件时图像被裁剪的原因是因为 recycleView
的高度是 40dp
,这是 pdf 项目的高度。当您尝试在不修改现有项目的情况下添加新项目时,recycleView
高度保持不变,即 40dp
。要强制执行最小高度 80dp
(这是图像布局的当前高度),我们可以使用 minHeight
,如下所示:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="80dp"
tools:listitem="@layout/document_item"
/>
您还可以修改 pdf 项目布局以使 pdf center_vertically
与图像项目对齐,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_margin="5dp">
<TextView
android:layout_width="150dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:gravity="center"
android:background="@drawable/ic_round"
android:backgroundTint="#888888"
android:text="PDF"
android:textColor="@android:color/white"/>
</LinearLayout>
干杯:)
如果它对其他人有帮助, 的 Kotlin 版本在下面进行了一些小的重构,但 100% 感谢@MariosP。他的回答为我们挽救了一切!
RecyclerView 设置(这是来自片段,在 onViewCreated 中调用):
private fun setupRecyclerView() {
val flexBoxLayoutManager = FlexboxLayoutManager(requireContext(), FlexDirection.ROW, FlexWrap.NOWRAP)
with(recycler_view) {
layoutManager = flexBoxLayoutManager
adapter = myAdapter
}
}
适配器设置:
var items : List<Item>
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bindItem(items[position])
}
在 ViewHolder 中:
class MyViewHolder(private val itemView: View): RecyclerView.ViewHolder(itemView) {
fun bindItem(item: Item) {
// Do things with item
updateLayoutParamsToAllowHorizontalScrolling()
}
private fun updateLayoutParamsToAllowHorizontalScrolling() {
(itemView.layoutParams as? FlexboxLayoutManager.LayoutParams)?.let {
it.flexShrink = 0.0f
it.alignSelf = AlignItems.FLEX_START
}
}
}
我正在尝试实现水平滚动的 RecyclerView
,所以我使用的是水平方向的 LinearLayoutManager
。问题是我使用 2 种不同类型的高度不同的项目填充 RecyclerView。这是我为项目使用的布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp">
<LinearLayout
android:id="@+id/document_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/ic_rounded"
android:backgroundTint="@color/ms_black_ms_gray"
android:gravity="center"
android:layout_gravity="bottom"
android:padding="5dp"
android:paddingStart="15dp">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="13sp"
android:singleLine="true"
android:maxWidth="80dp"
tools:text="example_form"/>
<TextView
android:id="@+id/format"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="13sp" />
…
</LinearLayout>
<android.support.v7.widget.CardView
android:id="@+id/image_view"
android:layout_width="120dp"
android:layout_height="80dp"
android:layout_gravity="bottom"
app:cardCornerRadius="25dp"
app:cardElevation="0dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/preview_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"/>
…
</RelativeLayout>
</android.support.v7.widget.CardView>
这是包含RecyclerView
的布局,基本上是这样的:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="14dp"
android:paddingEnd="14dp">
<ImageView
android:id="@+id/attach"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_gravity="bottom"
android:layout_marginBottom="19dp"
android:visibility="visible"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginBottom="10dp"
android:layout_marginTop="5dp"
android:padding="3dp"
android:foreground="@drawable/ic_rounded_stroke"
android:foregroundTint="@color/white">
<android.support.constraint.ConstraintLayout
android:id="@+id/chatEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ic_rounded"
android:foreground="@drawable/ic_rounded_stroke"
android:padding="6dp"
android:visibility="visible">
<EditText
android:id="@+id/editText"
android:textSize="17sp"
android:textColor="#121212"
android:letterSpacing="-0.02"
android:lineSpacingExtra="0sp"
android:padding="10dp"
android:paddingStart="15dp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="5"
android:hint="@string/chat_hint"
android:inputType="textCapSentences|textMultiLine"
android:maxLength="2500"
android:background="@null"
app:layout_constraintRight_toLeftOf="@id/buttonsContainer"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/send"
android:layout_gravity="bottom"
android:visibility="visible"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingBottom="10dp"
android:paddingTop="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="#ffffff"
android:letterSpacing="-0.02"
android:gravity="center_horizontal"
android:text="@string/send"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
<android.support.v7.widget.RecyclerView
android:id="@+id/filesList"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:paddingTop="5dp"
android:paddingEnd="5dp"
android:visibility="gone"
app:layout_constraintRight_toLeftOf="@id/send"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/editText"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>
</LinearLayout>
</LinearLayout>
我使用的是单个 ViewHolder
,我只是更改了 2 个子视图的可见性。
我期望得到的结果是这个:
但我得到的是这个; CardView 被切成两半,使用第二种类型的项目的高度:
我看到了Google’s Flexbox
。所以,我尝试实现 FlexboxLayoutManager
:
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(getContext());
layoutManager.setFlexDirection(FlexDirection.ROW);
layoutManager.setFlexWrap(FlexWrap.NOWRAP);
我正在使用 row
方向,如果它不适合单行,它会在下一行显示项目。所以,我也加了No_wrap
。现在它在一行中显示项目但不提供滚动。同样在这种情况下,它会尝试通过减小项目的宽度来将所有项目放在一行中。
我也玩过 flex box 示例应用程序,但是我得不到我想要的结果。
有没有什么办法可以通过集成RecyclerView的Flexbox来实现水平滚动?或者我应该使用不同的方法?
谢谢
编辑
感谢您的提示和一切,但它并没有解决它。因此,我将代码精简到最低限度以重现这一点。
主要活动:
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CODE = 1;
private RecyclerView recyclerView;
private FilesAdapter filesAdapter;
private List<File> filesList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerView);
LinearLayoutManager filesLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(filesLayoutManager);
filesAdapter = new FilesAdapter(filesList);
recyclerView.setAdapter(filesAdapter);
ImageView attach = findViewById(R.id.attach);
attach.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(Intent.createChooser(intent,"Select Files"), REQUEST_CODE);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
try {
if (data != null) {
List<File> uriList = new ArrayList<>();
if (data.getClipData() != null) { // Multiple files
for (int i = 0; i < data.getClipData().getItemCount(); i++) {
Uri uri = data.getClipData().getItemAt(i).getUri();
Pair<Boolean, File> isValid = isFileValid(uri);
if (isValid.first) {
uriList.add(isValid.second);
}
}
} else { // Single file
Uri uri = data.getData();
Pair<Boolean, File> isValid = isFileValid(uri);
if (isValid.first) {
uriList.add(isValid.second);
}
}
if (uriList.size() > 0) {
for (File file : uriList) {
filesList.add(filesList.size(), file);
filesAdapter.notifyItemInserted(filesList.size());
}
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
super.onActivityResult(requestCode, resultCode, data);
}
private Pair<Boolean, File> isFileValid(Uri uri) throws NullPointerException {
Pair<Boolean, File> defaultResponse = Pair.create(false, null);
Cursor c = getContentResolver().query(uri, null, null, null, null);
if (c != null) {
c.moveToFirst();
String filename = c.getString(c.getColumnIndex(OpenableColumns.DISPLAY_NAME));
if (isSupported(filename)) {
c.close();
return Pair.create(true, new File(StringUtils.endsWithIgnoreCase(filename, ".pdf") ? DOCUMENT : IMAGE));
} else {
Toast.makeText(this, "File format not supported", Toast.LENGTH_SHORT).show();
c.close();
return defaultResponse;
}
}
return defaultResponse;
}
private boolean isSupported(String filename) {
String[] supportedFormats = { ".pdf", ".jpg", ".gif", ".png" };
for (String format : supportedFormats) {
if (StringUtils.endsWithIgnoreCase(filename, format)) {
return true;
}
}
return false;
}
}
主要activity布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/attach"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_marginBottom="19dp"
android:padding="10dp"
android:src="@drawable/ic_attach" />
</LinearLayout>
文件:
public class File {
public enum Type {
DOCUMENT,
IMAGE
}
private Type type;
public File(Type type) {
this.type = type;
}
public Type getType() {
return type;
}
}
文件适配器:
public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.BaseViewHolder> {
private List<File> files;
public FilesAdapter(List<File> files) {
this.files = files;
}
@NonNull
@Override
public FilesAdapter.BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(viewType == 0 ? R.layout.document_item : R.layout.image_item, parent, false);
if (viewType == 0) {
return new DocumentViewHolder(view);
} else {
return new ImageViewHolder(view);
}
}
@Override
public void onBindViewHolder(@NonNull FilesAdapter.BaseViewHolder viewHolder, int position) {
viewHolder.bind(files.get(position));
}
@Override
public int getItemViewType(int position) {
if (files.get(position).getType() == File.Type.DOCUMENT) {
return 0;
} else {
return 1;
}
}
@Override
public int getItemCount() {
return files.size();
}
abstract static class BaseViewHolder extends RecyclerView.ViewHolder {
public BaseViewHolder(@NonNull View itemView) {
super(itemView);
}
abstract void bind(File file);
}
static class ImageViewHolder extends BaseViewHolder {
public ImageViewHolder(@NonNull View itemView) {
super(itemView);
}
@Override
void bind(File file) { }
}
static class DocumentViewHolder extends BaseViewHolder {
public DocumentViewHolder(@NonNull View itemView) {
super(itemView);
}
public void bind(File file) { }
}
}
文档项:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="150dp"
android:layout_height="40dp"
android:background="@drawable/ic_rounded"
android:backgroundTint="#888888"
android:layout_margin="5dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="PDF"
android:textColor="@android:color/white"/>
</LinearLayout>
图片项:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="120dp"
android:layout_height="80dp"
android:layout_margin="5dp"
app:cardBackgroundColor="#000000"
app:cardCornerRadius="10dp"
app:cardElevation="0dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="IMAGE"
android:textColor="@android:color/white"/>
</androidx.cardview.widget.CardView>
如果我先 select 一个图像,然后是几个 pdf,它工作正常:
但如果我先 select 3 个 pdf,然后是图像,就会发生这种情况:
知道如何解决这个问题吗?
为你的 RecyclerView 试试这个:
android:layout_height="wrap_content"
因为包含你的 RecyclerView 的 XML 文件在这里不完整我不能确定但是如果你的 RecyclerView 在另一个限制它的父视图中,那么我想使用 wrap_content 作为RecyclerView 的高度加上一些调整应该可以解决它。
另外,请注意,您将 RecyclerView 限制在顶部“editText”的底部,这样可能会阻止您的 RecyclerView 扩展。
首先,我认为您的主要布局有点过于复杂。您可以在单个 ConstraintLayout
中完成所有操作(如果您需要围绕特定项目设置框架背景,我建议使用使用 Barrier
和 Guideline
布置的纯 View
实例s - 参见 https://medium.com/better-programming/essential-components-of-constraintlayout-7f4026a1eb87)
另一个 and/or 改进是不使用 right/left 约束,而是 start/end。这也为 RTL 显示准备了布局。
此外,我强烈建议对 RecyclerView
中的不同项目使用单独的布局文件和 ViewHolder
s。
正如其他人在评论中指出的那样,您的 RecyclerView
是使用 match_parent
布局的,这反过来又可以裁剪您的视图。您可能需要设置此 wrap_content
.
与此同时,您可能还想更新依赖项以使用 Android Jetpack 并放弃支持库。
您所要做的就是将 recyclerview 高度设置为最大项目的高度,在您的例子中是图像项目。
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="wrap_content"
android:layout_height="80dp" />
我在另一个项目中遇到了类似的问题,我使用 Google 库 FlexboxLayoutManager 解决了它。
- 获取最新的 FlexboxLayoutManager 库 (https://github.com/google/flexbox-layout) 并将其添加到您的 grandle 依赖项中(实现 'com.google.android:flexbox:2.0.1')
- 在您的 Activity 中添加以下代码行:
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(this); layoutManager.setFlexDirection(FlexDirection.ROW); layoutManager.setFlexWrap(FlexWrap.NOWRAP); recyclerView.setLayoutManager(layoutManager);
- 要使 FlexboxLayoutManager 与水平滚动一起工作,请在 BaseViewHolder class 的适配器 (FilesAdapter) 中添加以下代码:
abstract static class BaseViewHolder extends RecyclerView.ViewHolder { public BaseViewHolder(@NonNull View itemView) { super(itemView); ViewGroup.LayoutParams lp = itemView.getLayoutParams(); if (lp instanceof FlexboxLayoutManager.LayoutParams) { FlexboxLayoutManager.LayoutParams flexboxLp = (FlexboxLayoutManager.LayoutParams) lp; flexboxLp.setFlexShrink(0.0f); flexboxLp.setAlignSelf(AlignItems.FLEX_START); //this will align each itemView on Top or use AlignItems.FLEX_END to align it at Bottom } } abstract void bind(File file); }
首先选择 pdf 文件时图像被裁剪的原因是因为 recycleView
的高度是 40dp
,这是 pdf 项目的高度。当您尝试在不修改现有项目的情况下添加新项目时,recycleView
高度保持不变,即 40dp
。要强制执行最小高度 80dp
(这是图像布局的当前高度),我们可以使用 minHeight
,如下所示:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="80dp"
tools:listitem="@layout/document_item"
/>
您还可以修改 pdf 项目布局以使 pdf center_vertically
与图像项目对齐,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_margin="5dp">
<TextView
android:layout_width="150dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:gravity="center"
android:background="@drawable/ic_round"
android:backgroundTint="#888888"
android:text="PDF"
android:textColor="@android:color/white"/>
</LinearLayout>
干杯:)
如果它对其他人有帮助,
RecyclerView 设置(这是来自片段,在 onViewCreated 中调用):
private fun setupRecyclerView() {
val flexBoxLayoutManager = FlexboxLayoutManager(requireContext(), FlexDirection.ROW, FlexWrap.NOWRAP)
with(recycler_view) {
layoutManager = flexBoxLayoutManager
adapter = myAdapter
}
}
适配器设置:
var items : List<Item>
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bindItem(items[position])
}
在 ViewHolder 中:
class MyViewHolder(private val itemView: View): RecyclerView.ViewHolder(itemView) {
fun bindItem(item: Item) {
// Do things with item
updateLayoutParamsToAllowHorizontalScrolling()
}
private fun updateLayoutParamsToAllowHorizontalScrolling() {
(itemView.layoutParams as? FlexboxLayoutManager.LayoutParams)?.let {
it.flexShrink = 0.0f
it.alignSelf = AlignItems.FLEX_START
}
}
}