gpt4 book ai didi

android - 带有附件的邮件的 RecyclerView 无法正确显示附件

转载 作者:行者123 更新时间:2023-11-30 02:01:45 25 4
gpt4 key购买 nike

我有一个 MessageAdapter 扩展 RecyclerView.Adapter 用于消息。这是它在正常工作时看起来应该的样子。您单击卡片,它会展开以显示图像。这只会发生在有图像的消息上:

enter image description here enter image description here

但是有时我向下滚动并向上滚动,图像就这样消失了:

enter image description here

有时我在 RecyclerView 上上下滚动,不应该有附件的消息有一个:

enter image description here enter image description here

在我的 MessageAdapter 中,我有两个 ViewType,一个用于 Header Message,另一个用于 Comment Messages。

这是我的 MessageAdapter 的样子:

public class MessageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

private static final int TYPE_MESSAGE_HEADER = 0;
private static final int TYPE_MESSAGE_COMMENT = 1;

private Context mContext;
private Message mOriginalMessage;
private List<Message> mMessages;

public MessageAdapter(Context context) {
this.mContext = context;
}

public void setOriginalMessage(Message originalMessage) {
this.mOriginalMessage = originalMessage;
}

public void setMessages(List<Message> messages) {
this.mMessages = new ArrayList<>(messages);
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_MESSAGE_HEADER) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_header,
parent, false);
return new MessageViewHolder(v, viewType);
} else {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_comment,
parent, false);
return new MessageViewHolder(v, viewType);
}
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

final MessageViewHolder messageViewHolder = (MessageViewHolder) holder;
int viewType = holder.getItemViewType();

switch (viewType) {
case TYPE_MESSAGE_HEADER:

if (messageViewHolder.mIsViewExpanded && mOriginalMessage.getAttachment() != null)
animateHeader(messageViewHolder);

// Other initialization stuff

// Set the image
if (mOriginalMessage.getAttachment() != null) {
messageViewHolder.mHeaderImage.setVisibility(View.INVISIBLE);
messageViewHolder.mHeaderShowTextView.setVisibility(View.VISIBLE);
messageViewHolder.mHeaderShowTextView.setText("Show Attachment");
String attachmentUrl = mOriginalMessage.getAttachment().getImageUrl();
if (messageViewHolder.mIsViewExpanded) {
Picasso.with(mContext)
.load(attachmentUrl)
.into(messageViewHolder.mHeaderImage);
}

messageViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animateHeader(messageViewHolder);
}
});
}

break;
case TYPE_MESSAGE_COMMENT:

Message message = mMessage.get(position - 1);

if (messageViewHolder.mIsViewExpanded && message.getAttachment() != null)
animateComment(messageViewHolder);

// Other initialization stuff

// Show attachment if there is an attachment
if (message.getAttachment() != null) {
messageViewHolder.mMessageImage.setVisibility(View.INVISIBLE);
messageViewHolder.mMessageShowTextView.setVisibility(View.VISIBLE);
messageViewHolder.mMessageShowTextView.setText("Show Attachment");
String attachmentUrl = message.getAttachment().getImageUrl();
if (messageViewHolder.mIsViewExpanded) {
Picasso.with(mContext)
.load(attachmentUrl)
.into(messageViewHolder.mMessageImage);
}

messageViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animateComment(messageViewHolder);
}
});
}
break;
default:
break;
}

}

@Override
public int getItemViewType(int position) {
if (isPositionHeader(position)) {
return TYPE_MESSAGE_HEADER;
}
return TYPE_MESSAGE_COMMENT;
}

private boolean isPositionHeader(int position) {
return position == 0;
}

// GUESSING SOMETHING WRONG HERE?
@Override
public int getItemCount() {
if (mOriginalMessage != null && mMessages != null) {
if (!mMessages.isEmpty())
return mMessages.size() + 1;
else
return 1;
} else if (mMessages != null) {
if (!mMessages.isEmpty())
return mMessages.size();
}
return 0;
}

private void animateHeader(final MessageViewHolder messageViewHolder) {

if (messageViewHolder.mOriginalHeight == 0)
messageViewHolder.mOriginalHeight = messageViewHolder.itemView.getHeight();

ValueAnimator valueAnimator;
if (!messageViewHolder.mIsViewExpanded) {
messageViewHolder.mHeaderImage.setVisibility(View.VISIBLE);
messageViewHolder.mHeaderImage.setEnabled(true);
messageViewHolder.mIsViewExpanded = true;
valueAnimator = ValueAnimator
.ofInt(messageViewHolder.mOriginalHeight, commentViewHolder.mOriginalHeight
+ (int) (messageViewHolder.mOriginalHeight * 0.8) + 10);
messageViewHolder.mHeaderShowTextView.setText("Hide Attachment");
} else {
messageViewHolder.mIsViewExpanded = false;
valueAnimator = ValueAnimator.ofInt(messageViewHolder.mOriginalHeight + (int) (messageViewHolder.mOriginalHeight * 0.8)
+ 10, messageViewHolder.mOriginalHeight);
Animation a = new AlphaAnimation(1.00f, 0.00f);

a.setDuration(200);
a.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
messageViewHolder.mHeaderShowTextView.setText("Show Attachment");
}

@Override
public void onAnimationEnd(Animation animation) {
messageViewHolder.mAttachmentImage.setVisibility(View.INVISIBLE);
messageViewHolder.mHeaderImage.setEnabled(false);
}

@Override
public void onAnimationRepeat(Animation animation) {

}
});

messageViewHolder.mHeaderImage.startAnimation(a);
}

valueAnimator.setDuration(400);
valueAnimator.setInterpolator(new BakedBezierInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
messageViewHolder.itemView.getLayoutParams().height = (int) animation.getAnimatedValue();
messageViewHolder.itemView.requestLayout();
}
});

valueAnimator.start();
}

private void animateComment(final MessageViewHolder messageViewHolder) {

if (messageViewHolder.mOriginalHeight == 0)
messageViewHolder.mOriginalHeight = messageViewHolder.itemView.getHeight();

ValueAnimator valueAnimator;
if (!messageViewHolder.mIsViewExpanded) {
messageViewHolder.mMessageImage.setVisibility(View.VISIBLE);
messageViewHolder.mMessageImage.setEnabled(true);
messageViewHolder.mIsViewExpanded = true;
valueAnimator = ValueAnimator
.ofInt(messageViewHolder.mOriginalHeight, messageViewHolder.mOriginalHeight
+ (int) (messageViewHolder.mOriginalHeight * 0.8) + 10);
messageViewHolder.mMessageShowTextView.setText("Hide Attachment");
} else {
messageViewHolder.mIsViewExpanded = false;
valueAnimator = ValueAnimator
.ofInt(messageViewHolder.mOriginalHeight + (int) (messageViewHolder.mOriginalHeight * 0.8)
+ 10, messageViewHolder.mOriginalHeight);
Animation a = new AlphaAnimation(1.00f, 0.00f);

a.setDuration(200);
a.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
messageViewHolder.mMessageShowTextView.setText("Show Attachment");
}

@Override
public void onAnimationEnd(Animation animation) {
messageViewHolder.mMessageImage.setVisibility(View.INVISIBLE);
messageViewHolder.mMessageImage.setEnabled(false);
}

@Override
public void onAnimationRepeat(Animation animation) {

}
});

messageViewHolder.mMessageImage.startAnimation(a);
}

valueAnimator.setDuration(300);
valueAnimator.setInterpolator(new BakedBezierInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
messageViewHolder.itemView.getLayoutParams().height = (int) animation.getAnimatedValue();
messageViewHolder.itemView.requestLayout();
}
});

valueAnimator.start();
}

public class MessageViewHolder extends RecyclerView.ViewHolder {

// Header
private ImageView mHeaderImage;
private TextView mHeaderShowTextView;

// Comment
private ImageView mMessageImage;
private TextView mMessageShowTextView;

// Variables for View
private int mOriginalHeight = 0;
private boolean mIsViewExpanded = false;

private int mHolderId;

public MessageViewHolder(View itemView, int viewType) {
super(itemView);
if (viewType == TYPE_MESSAGE_HEADER)
initHeaderViews(itemView);
else if (viewType == TYPE_MESSAGE_COMMENT)
initCommentViews(itemView);
}

private void initHeaderViews(View view) {
mHeaderImage = (ImageView) view.findViewById(R.id.header_image);
mHeaderShowTextView = (TextView) view.findViewById(R.id.header_show_textview);
mHeaderShowTextView.setVisibility(View.INVISIBLE);

if (!mIsViewExpanded) {
mHeaderImage.setEnabled(false);
mHeaderImage.setVisibility(View.GONE);
}

mHolderId = TYPE_MESSAGE_HEADER;
}

private void initCommentViews(View view) {
mMessageImage = (ImageView) view.findViewById(R.id.itemAttachmentImage);
mMessageShowTextView = (TextView) view.findViewById(R.id.showItemAttachment);
mMessageShowTextView.setVisibility(View.INVISIBLE);

if (!mIsViewExpanded) {
mMessageShowTextView.setText("Show Attachment");
mMessageImage.setEnabled(false);
mMessageImage.setVisibility(View.GONE);
}

mHolderId = TYPE_MESSAGE_COMMENT;
}

}

}

有没有办法更好更准确地做到这一点?具体来说,最大的问题是消除任何不一致以及是否可以解耦此代码。

我怎样才能获得正确的邮件以仅正确显示其附件?如何在向上或向下滚动时将图像保留在卡片中?当我添加新评论时,这也开始变得困惑,因为现在有一个 N + 1 问题。

具体来说,我想知道是否有更好的方法来处理多个 ViewHolders,而不是尝试控制 RecyclerViewoffset 值.

更新:

通过在 Fragment 中使用以下内容,我能够降低我的适配器的一些复杂性我正在初始化我的 RecyclerView.Adapter:

public void setParentMessage(Message parentMessage) {
this.mParentMessage = parentMessage;
mAllMessages = new ArrayList<>();
mAllMessages.add(mParentMessage);
}

public void setMessages(List<Messages> messages) {
this.mMessages = messages;
mAllMessages.addAll(mMessages);
}

然后我在开始时初始化我的适配器:

mMessageAdapter.setMessages(mAllMessages);

然后,如果我必须向我的列表中添加一个新的 Message 对象,我可以简单地执行以下操作:

public void addComment(Message message) {
mMessageAdapter.addItem(mMessageAdapter.getItemCount(), message);
mRecyclerView.scrollToPosition(mMessageAdapter.size() - 1);
}

在我的 MessageAdapter 中,我有以下内容来添加新的消息评论:

public void addItem(int position, Message message) {
mMessages.add(position, message);
notifyItemInserted(position);
}

这意味着我可以改变它:

@Override
public int getItemCount() {
if (mOriginalMessage != null && mMessages != null) {
if (!mMessages.isEmpty())
return mMessages.size() + 1;
else
return 1;
} else if (mMessages != null) {
if (!mMessages.isEmpty())
return mMessages.size();
}
return 0;
}

对此:

@Override
public int getItemCount() {
if (mMessages != null) {
if (!mMessages.isEmpty())
return mMessages.size();
}
return 0;
}

在我的 onBindViewHolder 方法中,我不再需要跟踪偏移量,所以这发生了变化:

Message message = mMessage.get(position - 1);

收件人:

Message message = mMessage.get(position);

此外,我将 MessageViewHolder 解耦为两个单独的 ViewHolder 类:

public class MessageHeaderViewHolder extends RecyclerView.ViewHolder {

// Header
private ImageView mHeaderImage;
private TextView mHeaderShowTextView;

// Variables for View
private int mOriginalHeight = 0;
private boolean mIsViewExpanded = false;

private int mHolderId;

public MessageHeaderViewHolder(View itemView, int viewType) {
super(itemView);
initHeaderViews(itemView);
}

private void initHeaderViews(View view) {
mHeaderImage = (ImageView) view.findViewById(R.id.header_image);
mHeaderShowTextView = (TextView) view.findViewById(R.id.header_show_textview);
mHeaderShowTextView.setVisibility(View.INVISIBLE);

if (!mIsViewExpanded) {
mHeaderImage.setEnabled(false);
mHeaderImage.setVisibility(View.GONE);
}

mHolderId = TYPE_MESSAGE_HEADER;
}

private void initOnClickListener() {
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animate(v);
}
});
}

private void removeClickListener() {
if (itemView.hasOnClickListeners())
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// THIS CODE DOESN'T WORK AS THOUGHT.
// Empty click listener to keep itemSelectableBackground.
}
});
}

private void animate(View v) {
// All animation code for header moved here
}

}

另一个 ViewHolder 也是一样:

public class MessageCommentViewHolder extends RecyclerView.ViewHolder {

// Comment
private ImageView mMessageImage;
private TextView mMessageShowTextView;

// Variables for View
private int mOriginalHeight = 0;
private boolean mIsViewExpanded = false;

private int mHolderId;

public MessageCommentViewHolder(View itemView, int viewType) {
super(itemView);
initCommentViews(itemView);
}

private void initCommentViews(View view) {
mMessageImage = (ImageView) view.findViewById(R.id.itemAttachmentImage);
mMessageShowTextView = (TextView) view.findViewById(R.id.showItemAttachment);
mMessageShowTextView.setVisibility(View.INVISIBLE);

if (!mIsViewExpanded) {
mMessageShowTextView.setText("Show Attachment");
mMessageImage.setEnabled(false);
mMessageImage.setVisibility(View.GONE);
}

mHolderId = TYPE_MESSAGE_COMMENT;
}

private void initOnClickListener() {
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animate(v);
}
});
}

private void removeClickListener() {
if (itemView.hasOnClickListeners())
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// THIS CODE DOESN'T WORK AS THOUGHT.
// Empty click listener to keep itemSelectableBackground.
}
});
}

private void animate(View v) {
// All animation code for header moved here
}

}

这意味着在我的 onBindViewHolder 方法中,我可以为每种类型的项目执行以下操作(请记住,现在将有两种类型的 ViewHolder,所以 messageViewHolder 将更改为 headerViewHoldercommentViewHolder 或类似内容):

if (message.getAttachment() != null) {
messageViewHolder.mMessageImage.setVisibility(View.INVISIBLE);
messageViewHolder.mMessageShowTextView.setVisibility(View.VISIBLE);
messageViewHolder.mMessageShowTextView.setText("Show Attachment");
String attachmentUrl = message.getAttachment().getImageUrl();
Picasso.with(mContext)
.load(attachmentUrl)
.into(messageViewHolder.mMessageImage);

messageViewHolder.initOnClickListener();
} else {
messageViewHolder.removeClickListener();
messageViewHolder.mMessageImage.setVisibility(View.GONE);
messageViewholder.mMessageShowTextView.setVisibility(View.GONE);
}

它现在工作正常,虽然这是一个非常 hacky 的解决方案,但我计划使用 doubleA 的答案并在本周末使这段代码更加优化。仍然存在的一个问题是某些项目将具有 itemSelectableBackground 并且可以 clickable 而其他项目则不是,据我了解 removeClickListener() 应该初始化空的 View.OnClickListener 从而使项目可点击,因此显示 itemSelectableBackground 但事实并非如此? Log 输出表明我正在正确初始化监听器和图像。

最佳答案

这是回收者观点的一个常见问题,实际上是我最近的一个面试问题。当您使用回收器 View 和 View 持有者时,它会按照它说的做......回收 View 。因此,如果您开始向下滚动并且一个 View 附有图像并且您显示该图像,然后当该 View 被回收并且您放入其中的新数据没有与之关联的图像时,您的代码不会明确告诉父 View 持有者隐藏其中的 ImageView 。因此,您的图片会出现在回收 View 中,因为它已经存在并且只是被回收了。

这是我的建议

if (message.getAttachment() != null) {
//all your fun view binding stuff.
} else {
messageViewHolder.mMessageImage.setVisibility(View.GONE);
}

此外,我建议您将 View 绑定(bind)代码放入您的 View 持有者中,并在必要时使用 2 个具有相同布局的不同 View 持有者。它将缩短您的 onBindViewHolder 调用并将不同的 View 绑定(bind)代码与与之关联的 View 持有者链接起来。这是我的一个回收器 View 适配器的示例。

public class ProgramRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

/**
This is an abstract class that all of my viewholders inherit from.
This is a contract telling me that any subclasses that inherit from this
base class are required to write their own `public void bind(int position,
Program program);` method.
*/
abstract class ProgramBaseViewHolder extends RecyclerView.ViewHolder {

public ProgramBaseViewHolder(View itemView) {
super(itemView);
}

public abstract void bindDataToView(int position, Program program);
}

我意识到关键字 bind 在这个 View 持有者中被多次使用,并且他们在做不同的事情。 @Bind 和 Butterknife.bind 是名为 Butterknife 的 View 绑定(bind)库的一部分,该库由为您提供 Picasso 的同一批好人制作。 “绑定(bind)”的这种用法等同于您的 findViewById() 调用。抽象类的绑定(bind)只是将数据绑定(bind)到适配器中的 View 的方法的通用名称。我已将 bind 重命名为 bindDataToView 以便更明确一些。

/**
This is the Airtime view that holds airtimes. It is a view holder that
inherits from my base view holder and implements its own version if bind.
*/
class AirtimeViewHolder extends ProgramBaseViewHolder {
@Bind(R.id.program_airtimes)
TextView mProgramAirtimes;

static final int viewType = 0;

public AirtimeViewHolder(View itemView) {
super(itemView);
/**This call to butterknife can be replaced with an
itemView.findViewById(R.id.yourview) */
ButterKnife.bind(this, itemView);
}

//This is where you set your text and hide or show your views.
@Override
public void bindDataToView(int position, Program program) {
List<Airtime> airtimes = program.getAirtimes();
if (!airtimes.isEmpty()) {
mProgramAirtimes.setText(Utils.getFriendlyAirtimes(airtimes));
} else {
mProgramAirtimes.setText(
Utils.getFriendlyAirTime(program.getAirtime()));
}
}
}

/**
This is the Description view that holds descriptions. It is a view holder
that inherits from my base view holder and implements its own version if
bind.
*/
class DescriptionViewHolder extends ProgramBaseViewHolder {
@Bind(R.id.description_card_layout)
TextView mProgramDescription;

static final int viewType = 1;

public DescriptionViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}

@Override
public void bindDataToView(int position, Program program) {
mProgramDescription.setText(Html.fromHtml(program.getFullDescription()));
}
}
//This is another type of view with another different type of layout.
class HostsViewHolder extends ProgramBaseViewHolder {
@Bind(R.id.card_view_host_name)
TextView mProgramHostName;

static final int viewType = 2;

public HostsViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}

@Override
public void bindDataToView(int position, Program program) {
mProgramHostName.setText(program.getHosts().get(position - 2).getDisplayName());
}
}
//Again another type of view extending my base view.
class CategoriesViewHolder extends ProgramBaseViewHolder {
@Bind(R.id.program_categories)
TextView mProgramCategories;
static final int viewType = 42;

public CategoriesViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}

@Override
public void bindDataToView(int position, Program program) {
List<Category> categoryList = program.getCategories();
StringBuilder stringBuilder = new StringBuilder();
for (Category category : categoryList) {
stringBuilder.append(category.getTitle())
.append(" ");
}
mProgramCategories.setText(stringBuilder.toString());
}
}

//This is where the normal looking recycler view code comes in.
private Context mContext;
private LayoutInflater mInflater;
private Program mProgramData;
private int mNextProgramId;

public ProgramRecyclerAdapter(Context context) {
mContext = context;
mInflater = LayoutInflater.from(mContext);
}

/**This method is where I am determining what view type each item in my list
will be. I wanted a single airtimes view followed by a single description
view and then X amount of hosts views and a single category view. I return
position in the third else if because the position helps me determine which
host name to display in the bindDataToViews call of the HostViewHolder.*/
@Override
public int getItemViewType(int position) {
if (position == AirtimeViewHolder.viewType) {
return AirtimeViewHolder.viewType;
} else if (position == DescriptionViewHolder.viewType) {
return DescriptionViewHolder.viewType;
} else if (position > DescriptionViewHolder.viewType
&& position <= DescriptionViewHolder.viewType + getHostsNum()) {
return position;
} else {
return CategoriesViewHolder.viewType;
}
}

//This method figures out how many hosts will be displayed
private int getHostsNum() {
if (mProgramData != null) {
return mProgramData.getHosts().size();
}
return 0;
}
// This method determines if I will show a category view or not.
private int getCategoriesNum() {
if (mProgramData != null && mProgramData.getCategories().size() > 0) {
return 1;
}
return 0;
}

/**This returns haw many items will be in the list. 1 Airtime view, 1
Description view, x amount of Host views and 0 or 1 category views */
@Override
public int getItemCount() {
return 2 + getHostsNum() + getCategoriesNum();
}

/** This returns the appropriate View holder for the requested view type that
was set by getItemViewType(). I pass the inflated parent view and the data.
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == AirtimeViewHolder.viewType) {
return new AirtimeViewHolder(mInflater.inflate(R.layout.airtime_card_layout, parent, false));
} else if (viewType == DescriptionViewHolder.viewType) {
return new DescriptionViewHolder(mInflater.inflate(R.layout.description_card_layout, parent, false));
} else if (viewType > DescriptionViewHolder.viewType
&& viewType <= DescriptionViewHolder.viewType + getHostsNum()) {
return new HostsViewHolder(mInflater.inflate(R.layout.hosts_card_layout, parent, false));
} else
return new CategoriesViewHolder(mInflater.inflate(R.layout.categories_card_layout, parent, false));
}

/*This method is what ties everything together. After I ensure that the data
is not null I call bindDataToView on a ProgramBaseViewHolder. Depending on
which type of subclass it is will determine which overridden bindData code to
use. */
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ProgramBaseViewHolder baseViewHolder = (ProgramBaseViewHolder) holder;
if (mProgramData != null) {
baseViewHolder.bindDataToView(position, mProgramData);
}
}

//This is used to set the data for this program
public void setProgramData(Program program) {
mProgramData = program;
}

public Program getProgramData() {
return mProgramData;
}

public boolean isEmpty() {
return mProgramData == null;
}
}

这是通话时间布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/card_margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/airtimes_label"
android:textSize="18dp"
android:textStyle="bold"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:layout_marginBottom="4dp"/>
<TextView
android:id="@+id/program_airtimes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textAppearance="@style/TextAppearance.AppCompat.Title" />
</LinearLayout>

这是我的主机布局。您会注意到我没有使用此处的大部分 View ,因为这是一个正在开发中的应用程序。

    <?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/host_card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/card_margin"
card_view:cardBackgroundColor="@color/white"
card_view:cardCornerRadius="2dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp" />
<ImageView
android:id="@+id/host_image"
android:layout_width="112dp"
android:layout_height="112dp"
android:layout_alignParentLeft="true"
android:visibility="gone"
android:layout_centerVertical="true"
android:layout_marginRight="8dp" />
<LinearLayout
android:id="@+id/details"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/host_image"
android:orientation="vertical">
<TextView
android:id="@+id/card_view_host_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:layout_margin="16dp"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:layout_gravity="left" />
<TextView
android:id="@+id/card_view_hosts_programs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:textStyle="bold"
android:textSize="12sp"
android:layout_marginBottom="16dp"
android:layout_gravity="left"/>
</LinearLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>

This is the view that is produced with some data. The Categories view is cut off but it is there.

关于android - 带有附件的邮件的 RecyclerView 无法正确显示附件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31362236/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com