我有一个包含不同 View Holder 的回收站 View 。
几个 View 持有者有 ImageView ,我将它们传递给 Glide 以显示图像。
问题是,当回收器 View 开始回收 View 时, ImageView 的宽度/高度是回收 View 的宽度/高度,然后它们会错误地显示图像。
这是我的 ImageView:
<ImageView
android:id="@+id/image"
android:layout_marginTop="@dimen/feed_item_margin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
这是传递给 Glide
Glide.with(itemView.getContext())
.load(Uri.parse(MediaUtils
.getMedia(feedContent).getMediaUrl()))
.placeholder(R.drawable.placeholder)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.crossFade().into(image);
这在 Recyclerview 开始回收之前效果很好,因此 Recyclerview 中的第一张图片看起来像这样,这就是它的外观。
但是,当您滚动离开该项目并向后滚动时,它看起来像这样:
因此图像已经变形并且不是父级的全宽。
我希望 ImageView 能够包裹内容,因为所有图像的高度都会不同等等。
为了测试这一点,我添加了这一行 holder.setIsRecyclable(false); 以防止回收这个特定的 holder 和所有显示的图像,然而,正如预期的那样,这产生了不和谐的效果。
然后我尝试在 OnViewRecycled 方法中重置 ImageView 的参数,如下所示:
@Override
public void onViewRecycled(AbstractHolder viewHolder){
super.onViewRecycled(viewHolder);
int position = viewHolder.getAdapterPosition();
IFeedContent content = mFeedContentList.get(position);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(0, (int) Utils.dpTopx(mContext,10),0,0);
params.gravity = Gravity.CENTER;
if(isImage(content)){
viewHolder.getImageView().setImageURI(null);
viewHolder.getImageView().setImageDrawable(null);
viewHolder.getImageView().setImageResource(0);
viewHolder.getImageView().setLayoutParams(params);
}
}
在此,我在 xml 中重新创建了参数,但它不起作用。 isImage() 方法只检查对象的 mimetype。
有人可以帮忙吗?这非常令人沮丧。
感谢任何帮助。
编辑 添加适配器
public class ContentFeedAdapter extends RecyclerView.Adapter<AbstractHolder> {
private List<IFeedContent> mFeedContentList;
private Context mContext;
private Activity mMainActivity;
private UserHomeFragment mUserHomeFragment;
private UserStreamFragment mUserStreamFragment;
private AbstractHolder mAbstractHolder;
private final Map<YouTubeThumbnailView, YouTubeThumbnailLoader> mThumbnailViewToLoaderMap;
private ArrayList<MyMediaPlayer> mMediaPlayerList = new ArrayList<>();
public ContentFeedAdapter(Context ctx, List<IFeedContent> contentList, Activity mainActivity, UserHomeFragment userHomeFragment, UserStreamFragment userStreamFragment){
this.mContext = ctx;
this.mFeedContentList = contentList;
this.mMainActivity = mainActivity;
this.mThumbnailViewToLoaderMap = new HashMap<YouTubeThumbnailView, YouTubeThumbnailLoader>();
this.mUserHomeFragment = userHomeFragment;
this.mUserStreamFragment = userStreamFragment;
}
@Override
public AbstractHolder onCreateViewHolder(ViewGroup parent, int viewType) {
mAbstractHolder = createAbstractHolder(viewType, parent);
return mAbstractHolder;
}
@Override
public void onBindViewHolder(final AbstractHolder holder, final int position) {
final IFeedContent content = mFeedContentList.get(position);
holder.bindData(content);
if((content.getMedia()!=null) && !content.getMedia().isEmpty()){
String mimeType = MediaUtils.getMedia(content).getMimeType();
if(mimeType.contains(mContext.getString(R.string.video)) || mimeType.contains(mContext.getString(R.string.audio)) && !mimeType.contains(mContext.getString(R.string.youtube))){
final ProgressBar progressBar = holder.getProgress();
final ImageView playButton = holder.getPlayImage();
final Button retryButton = holder.getRetryImage();
final RelativeLayout playerOverLay = holder.getPlayerOverlay();
final ImageView mediaThumb = holder.getMediaThumbnail();
final MyMediaPlayer player = new MyMediaPlayer(mContext, holder.getTextureView(), holder.getMediaControllerAnchor(), holder.getProgress(),
mimeType, MyConstants.SEEK_TO_DEFAULT, retryButton, playButton, playerOverLay, mediaThumb);
player.setRecyclerViewPosition(position);
mMediaPlayerList.add(player);
playButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
player.startVideo(MediaUtils.getMedia(content).getMediaUrl());
holder.getPlayImage().setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
}
});
}
}
}
/**
* Release all holders used for the
* thumbnail views
*/
public void releaseYouTubeHolders(){
mAbstractHolder.releaseHolders();
}
@Override
public int getItemViewType(int position){
int viewType = -1;
//Instantiate ViewHolder Utils
//
viewType = ViewHolderUtils.selectViewHolder(mFeedContentList.get(position));
return viewType;
}
@Override
public int getItemCount() {
return mFeedContentList.size();
}
@Override
public void onViewRecycled(AbstractHolder viewHolder){
super.onViewRecycled(viewHolder);
int position = viewHolder.getAdapterPosition();
IFeedContent content = mFeedContentList.get(position);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(0, (int) Utils.dpTopx(mContext,10),0,0);
params.gravity = Gravity.CENTER;
if(isImage(content)){
viewHolder.getImageView().setImageURI(null);
viewHolder.getImageView().setImageDrawable(null);
viewHolder.getImageView().setImageResource(0);
viewHolder.getImageView().setLayoutParams(params);
}
}
/**
* Create instance of
* compatible viewholder
*
* @param viewType
* @param parent
* @return
*/
private AbstractHolder createAbstractHolder(int viewType, ViewGroup parent) {
AbstractHolder holder = null;
switch (viewType) {
case MyConstants.HOLDER_TYPE_1:
holder = ViewHolder_Var1.create(parent, mUserHomeFragment, mUserStreamFragment);
break;
case MyConstants.HOLDER_TYPE_2:
holder = ViewHolder_Var2.create(parent, mUserHomeFragment, mUserStreamFragment);
break;
case MyConstants.HOLDER_TYPE_3:
holder = ViewHolder_Var3.create(parent, mUserHomeFragment, mUserStreamFragment);
L.i(getClass().getSimpleName(), "HOLDER 3");
//holder.setIsRecyclable(false);
break;
case MyConstants.HOLDER_TYPE_4:
holder = ViewHolder_Var4.create(parent, mUserHomeFragment, mUserStreamFragment);
L.i(getClass().getSimpleName(), "HOLDER 4");
break;
case MyConstants.HOLDER_TYPE_5:
holder = ViewHolder_Var5.create(parent, mUserHomeFragment, mUserStreamFragment);
L.i(getClass().getSimpleName(), "HOLDER 5");
break;
case MyConstants.HOLDER_TYPE_6:
holder = ViewHolder_Var6.create(parent, mUserHomeFragment, mUserStreamFragment);
L.i(getClass().getSimpleName(), "HOLDER 6");
break;
case MyConstants.HOLDER_TYPE_7:
holder = ViewHolder_Var7.create(parent, mUserHomeFragment, mUserStreamFragment);
L.i(getClass().getSimpleName(), "HOLDER 7");
break;
case MyConstants.HOLDER_TYPE_8:
holder = ViewHolder_Var8.create(parent, mUserHomeFragment, mUserStreamFragment);
L.i(getClass().getSimpleName(), "HOLDER 8");
break;
case MyConstants.HOLDER_TYPE_9:
holder = ViewHolder_Var9.create(parent, mUserHomeFragment, mUserStreamFragment);
break;
case MyConstants.HOLDER_TYPE_10:
holder = ViewHolder_Var10.create(parent, mThumbnailViewToLoaderMap, mUserHomeFragment, mUserStreamFragment);
}
return holder;
}
private boolean isImage(IFeedContent contentItem) {
if (MediaUtils.getMedia(contentItem) != null) {
String mimeType = MediaUtils.getMedia(contentItem).getMimeType();
if (mimeType.contains("image")) {
L.i(getClass().getSimpleName(), "IMAGE HERE");
return true;
} else {
L.i(getClass().getSimpleName(), "NO IMAGE HERE");
}
}
return false;
}
}
编辑 2 ViewHolder 3
public class ViewHolder_Var3 extends AbstractHolder {
@Bind(R.id.text_holder1) TextView heading;
@Bind(R.id.text_holder2) TextView body;
@Bind(R.id.image)ImageView image;
@Bind(R.id.tabs_layout)LinearLayout tabsLayout;
@Bind(R.id.hot)TextView hot;
@Bind(R.id.comments)TextView children;
@Bind(R.id.gif_label)TextView gifTag;
@Bind(R.id.user_name)TextView userName;
@Bind(R.id.tag1)TextView tag1;
@Bind(R.id.tag2)TextView tag2;
@Bind(R.id.tag3)TextView tag3;
@Bind(R.id.profile_pic) SimpleDraweeView profilePic;
private boolean mEllipsize;
private boolean mExpanded;
private UserHomeFragment mUserHomeFragment;
private UserStreamFragment mUserStreamFragment;
public ViewHolder_Var3(View itemView, UserHomeFragment userHomeFragment, UserStreamFragment userStreamFragment) {
super(itemView);
ButterKnife.bind(this, itemView);
mUserHomeFragment = userHomeFragment;
this.mUserStreamFragment = userStreamFragment;
}
@Override
public void bindData(final IFeedContent feedContent) {
userName.setText(feedContent.getAuthor().getDisplayName());
image.setImageResource(0);
image.setImageDrawable(null);
image.setImageURI(null);
TextView [] tagsArray = {tag1, tag2, tag3};
if (feedContent.getName() != null) {
heading.setText(feedContent.getName());
} else {
heading.setText(feedContent.getUrl());
}
if (feedContent.getName() != null) {
body.setText((feedContent.getMessage()));
} else {
body.setText(feedContent.getUrl());
}
Log.i(ViewHolder_Var3.class.getSimpleName(), "Number of lines: " + String.valueOf(body.getLineCount()));
if(!MediaUtils.getMedia(feedContent).getMimeType().equals("image/gif")){
gifTag.setVisibility(View.GONE);
Glide.with(itemView.getContext()).load(Uri.parse(MediaUtils.getMedia(feedContent).getMediaUrl())).placeholder(R.drawable.placeholder).diskCacheStrategy(DiskCacheStrategy.SOURCE).crossFade().into(image);
}else {
Glide.with(itemView.getContext()).load(Uri.parse(MediaUtils.getMedia(feedContent).getMediaUrl())).asGif().placeholder(R.drawable.placeholder).diskCacheStrategy(DiskCacheStrategy.RESULT).crossFade().into(image);
}
displayProfilePic(feedContent, profilePic);
Glide.with(itemView.getContext()).load(Uri.parse(MediaUtils.getMedia(feedContent).getMediaUrl())).placeholder(R.drawable.placeholder).diskCacheStrategy(DiskCacheStrategy.ALL).crossFade().into(image);
if(mUserHomeFragment==null){
userName.setEnabled(false);
profilePic.setEnabled(false);
}else{
userName.setEnabled(true);
profilePic.setEnabled(true);
}
userName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivityForResult(mUserHomeFragment, feedContent.getAuthor().getId(), feedContent.getParentId());
}
});
profilePic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivityForResult(mUserHomeFragment, feedContent.getAuthor().getId(), feedContent.getParentId());
}
});
long hotAmt = feedContent.getLikeCount() - feedContent.getDislikeCount();
hot.setText(String.valueOf(hotAmt));
children.setText(String.valueOf(feedContent.getChildCount()));
List<String> tagsList = feedContent.getTags();
populateTags(tagsList, tagsArray);
// if (feedContent.getTags().size() > 0) addTags(tags, tabsLayout);
ViewTreeObserver vto = body.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
ViewTreeObserver obs = body.getViewTreeObserver();
obs.removeOnGlobalLayoutListener(this);
Layout layout = body.getLayout();
if(layout!=null){
int lines = layout.getLineCount();
if(lines>0){
if(layout.getEllipsisCount(lines-1)>0){
mEllipsize = true;
}
}
}
}
});
body.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mEllipsize) {
if (!mExpanded) {
ObjectAnimator animation = ObjectAnimator.ofInt(body, "maxLines", 20);
//animation.setInterpolator(new BounceInterpolator());
animation.setDuration(200).start();
// Toast.makeText(itemView.getContext(), "I AM CLICKED", Toast.LENGTH_LONG).show();
mExpanded = true;
} else {
ObjectAnimator animation = ObjectAnimator.ofInt(body, "maxLines", 4);
//animation.setInterpolator(new BounceInterpolator());
animation.setDuration(200).start();
// Toast.makeText(itemView.getContext(), "I AM CLICKED", Toast.LENGTH_LONG).show();
mExpanded = false;
}
}
}
});
}
@Override
public ImageView getImageView(){
return image;
}
public static ViewHolder_Var3 create(ViewGroup parent, UserHomeFragment homeFragment, UserStreamFragment userStreamFragment){
View root = LayoutInflater.from(parent.getContext()).inflate(R.layout.feed_content_item_layout_var3, parent, false);
return new ViewHolder_Var3(root, homeFragment, userStreamFragment);
}
}
最佳答案
添加这一行
android:adjustViewBounds="true"
对于布局文件中的imageview,它会自动调整 ImageView 的大小。
在滑动中将 .crossFade() 更改为 .fitCenter()
关于android - RecyclerView 回收 ViewHolder Image View 尺寸错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33283493/
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c
我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file
我克隆了一个rails仓库,我现在正尝试捆绑安装背景:OSXElCapitanruby2.2.3p173(2015-08-18修订版51636)[x86_64-darwin15]rails-v在您的Gemfile中列出的或native可用的任何gem源中找不到gem'pg(>=0)ruby'。运行bundleinstall以安装缺少的gem。bundleinstallFetchinggemmetadatafromhttps://rubygems.org/............Fetchingversionmetadatafromhttps://rubygems.org/...Fe
在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee
我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie
我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa
这个问题在这里已经有了答案:Arraysmisbehaving(1个回答)关闭6年前。是否应该这样,即我误解了,还是错误?a=Array.new(3,Array.new(3))a[1].fill('g')=>[["g","g","g"],["g","g","g"],["g","g","g"]]它不应该导致:=>[[nil,nil,nil],["g","g","g"],[nil,nil,nil]]
尝试在我的RoR应用程序中实现计数器缓存列时出现错误Unknownkey(s):counter_cache。我在这个问题中实现了模型关联:Modelassociationquestion这是我的迁移:classAddVideoVotesCountToVideos0Video.reset_column_informationVideo.find(:all).eachdo|p|p.update_attributes:videos_votes_count,p.video_votes.lengthendenddefself.downremove_column:videos,:video_vot