- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个 MessageAdapter
扩展 RecyclerView.Adapter
用于消息。这是它在正常工作时看起来应该的样子。您单击卡片,它会展开以显示图像。这只会发生在有图像的消息上:
但是有时我向下滚动并向上滚动,图像就这样消失了:
有时我在 RecyclerView
上上下滚动,不应该有附件的消息有一个:
在我的 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
,而不是尝试控制 RecyclerView
的 offset
值.
更新:
通过在 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
将更改为 headerViewHolder
或 commentViewHolder
或类似内容):
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>
关于android - 带有附件的邮件的 RecyclerView 无法正确显示附件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31362236/
我想在文本区域中向许多其他用户发送电子邮件。在名为内容的文本区域中,如果我键入星号包围的“用户”,我想让它们填写每个电子邮件的用户名(“@”之前的文本)。每封电子邮件中的每个用户名都会产生很多不同。然
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: Problem when loading php file into variable (Load resu
我正在从数据库中提取信息,并尝试将其作为电子邮件发送。将从数据库中拉取多行数据。这就是我的代码的样子... 所有的信息邮件都很好。我的问题是,我想保留中断。例如,在标题之后,我想中断一下,然后开始备
当我使用我们使用 java 邮件的门户发送 TEXT 电子邮件时没有问题,但是,当我选择放置 HTML 内容并发送电子邮件时,会引发以下警报。花了几个小时搜索但没有有用的答案! 谁能帮忙 电子邮件主题
我有这个类,它处理 gmail 的登录。无论我输入什么电子邮件和密码,程序都会返回 session 。我不明白如何在返回 session 对象之前检查登录是否成功。 package mailActio
我设置的短信作为文本文件附在信中。我不明白为什么会这样。 replied letter example public void sendEmail(MimeMessage message, Strin
所以我正在制作一个网络系统,这个想法是当用户关闭浏览器时它会向我发送一封电子邮件。目前,用户正在使用 Javascript Ajax 来让 PHP 更新数据库的当前时间。当时间超过 5 分钟时,我希望
我想发送邮件,当产品从之前、日期和之后过期时,在 php 中,我在 php 中使用了 datediff mysql 函数,但如果产品过期日期类似于 31-1-2012 ,则不同值是不适合我的编码,请帮
我正在尝试设置一个邮件脚本,该脚本将首先从 mysql 运行一个简单的选择,并在消息中使用这些数组变量。然而,所有的变量并没有输出到消息体,只有一行变量。这是我的脚本: $sql1 = "SE
我最近一直在努力研究这个问题。是否有我可以使用并添加到其中的 android API?我想为电子邮件应用程序制作一个插件,但我不想制作整个电子邮件应用程序。 我非常想要一些已经可以处理发送和接收电子邮
嗨 我有一个 PHP 西类牙文网站。在此邮件正文中包含一个主题“Solicitud de cotización”,但该主题出现在热门邮箱中,如 Solicitud de cotización 。但它在
我想写一个脚本,使用 php 自动向我的客户发送电子邮件 我如何自动发送它,例如,如果他们输入他们的电子邮件。然后点击提交 我想自动发送这封邮件 其次,我的主机上是否需要 smtp 服务器?我可以在任
今天早上我已经解决了一个问题: Java Mail, sending multiple attachments not working 这次我遇到了一个稍微复杂一点的问题:我想将附件和图片结合起来。
下面是用于连接 IMAP 文件夹并对其执行操作的代码。所以我的问题是关于 javax.mail.Session 的,在这种情况下它会每秒重新创建一次(取决于 checkInbox() 的 hibern
我正尝试按照 http://www.tutorialspoint.com/java/java_sending_email.htm 上的指南发送电子邮件 Java 应用程序 当我尝试运行它时,从上面的链
我有一个包含 2 列 email 和 id 的表格。我需要找到密切相关的电子邮件。例如: john.smith12@example.com 和 john.smith12@some.subdomains
首先是一些信息: Debian 压缩 PHP 5.3.3 带有 mod_cgi 的 PHP 在这种情况下,我绝对必须使用 mail()。对于我所有的其他项目,我已经使用 SMTP 邮件。 我已将站点超
在对电子邮件主机的联系表单进行故障排除时,他们告诉我在 php 邮件功能的发件人地址中使用“-f”。 “-f”标志的作用是什么?为什么它可以解决允许发送电子邮件的问题?我阅读了一些文档,但不是很清楚。
一个简单的问题:群发邮件哪个性能好? mail() 函数或sendmail 流行的 PHP 列表管理器包使用哪个? 最佳答案 嗯,mail() 函数并不适合批量发送电子邮件,因为它会为您发送的每封
我正在制作一个 PHP 表单,允许用户上传附件并将其发送到我的电子邮件。我一直在寻找很长一段时间才能做到。最后,我找到了这个。 http://www.shotdev.com/php/php-mail/
我是一名优秀的程序员,十分优秀!