I use the RecyclerView list. There is a photo in the item. It is loaded via Picasso . At boot time, I made the placeholder to be just a gray rectangle. But its height is much more than the height of the picture. The height of the photo comes from the server. Played with her, but nothing happens, with fast scrolling in general, horror happens. If you scroll and wait for a stop, then the placeholders are replaced by a photo in turn and the list is twitching. For example, in the VC application, on the wall, placeholders are set to the height of the photo.

Item Layout

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingTop="10dp"> <TextView android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceSmall" android:layout_width="wrap_content" android:text="Medium Text" android:layout_marginLeft="10dp" android:textColor="#000000" android:id="@+id/text" android:textColorLink="@color/link_text" /> <ImageView android:layout_centerInParent="true" android:id="@+id/photoView" android:layout_height="wrap_content" android:layout_width="match_parent" android:adjustViewBounds="true" android:scaleType="centerCrop" android:layout_marginTop="15dp" android:layout_marginBottom="15dp" android:background="#B8B8B8" android:layout_marginLeft="10dp" android:layout_marginRight="10dp"/> <View android:layout_alignParentBottom="true" android:background="?android:attr/dividerVertical" android:layout_height="5dp" android:layout_width="match_parent"/> </LinearLayout> 

Adapter

 public class PostAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { static final int POST = 0; static final int LOAD_MORE = 1; boolean isLoading; int itemHeight; List<Post> list; AdapterListener listener; Context ctx; int layoutID; Picasso picasso; ColorDrawable drawable; public class PostHolder extends RecyclerView.ViewHolder implements OnClickListener, OnLongClickListener { ImageView photoView; TextView postText; PostHolder(View itemView) { super(itemView); photoView = (ImageView)itemView.findViewById(R.id.photoView); postText = (TextView)itemView.findViewById(R.id.text); itemView.setOnClickListener(this); } void bind(int position) { Post post = list.get(position); int w = post.getWidth(); int h = post.getHeight(); final String text = post.getText(); if (text.length() < 250) { postText.setText(text); } else { SpannableString ss = new SpannableString(text.substring(0, 250) + " Подробнее"); ClickableSpan clickableSpan = new ClickableSpan() { @Override public void onClick(View textView) { AlertDialog.Builder full = new AlertDialog.Builder(ctx); full.setMessage(text); full.create().show(); } @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setUnderlineText(false); } }; ss.setSpan(clickableSpan, ss.length() - 9, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); postText.setMovementMethod(LinkMovementMethod.getInstance()); postText.setHighlightColor(Color.TRANSPARENT); postText.setText(ss); } final String url = post.getUrl(); picasso .load(url) .placeholder(drawable) .resize(0,h) .into(photoView); } @Override public void onClick(View v) { int position = getAdapterPosition(); } @Override public boolean onLongClick(View v) { int position = getAdapterPosition(); return true; } } public class LoadMoreHolder extends RecyclerView.ViewHolder implements OnClickListener { Button load; ProgressBar pb; LoadMoreHolder(View itemView) { super(itemView); load = (Button)itemView.findViewById(R.id.load_more); pb = (ProgressBar)itemView.findViewById(R.id.loadmore_pb); load.setOnClickListener(this); } void bind() { load.setVisibility(isLoading ? View.GONE : View.VISIBLE); } @Override public void onClick(View v) { isLoading = true; load.setVisibility(View.GONE); listener.loadMore(); } } PostAdapter(List<Post> list, Context ctx, AdapterListener listener, int layoutID) { this.layoutID = layoutID; this.ctx = ctx; this.listener = listener; this.list = list; this.picasso = Picasso.with(ctx); drawable = new ColorDrawable(); drawable.setColor(Color.LTGRAY); } void setOnAdapterListener(AdapterListener listener) { this.listener = listener; } @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int itemType) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); if (itemType == POST) { View v = inflater.inflate(layoutID, parent, false); return new PostHolder(v); } else { View v = inflater.inflate(R.layout.loadmore, parent, false); return new LoadMoreHolder(v); } } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (getItemViewType(position) == POST) { ((PostHolder)holder).bind(position); } else { ((LoadMoreHolder)holder).bind(); } } @Override public int getItemViewType(int position) { if (position == getPostCount()) { return LOAD_MORE; } return POST; } public int getPostCount() { return list.size(); } @Override public int getItemCount() { int postCount = getPostCount(); if (postCount == 0) { return 0; } return getPostCount() + 1; } void loadingEnd() { isLoading = false; } public interface AdapterListener { void loadMore(); } } 

    1 answer 1

    In your markup at ImageView , if there is no objective reason to forcibly stretch the image to the width, you need to adjust the dimensions:

     <ImageView ... android:layout_height="wrap_content" android:layout_width="wrap_content" ... /> 

    As for the passage:

     ... picasso .load(url) .placeholder(drawable) .resize(0,h) .into(photoView); ... 

    and more specifically:

     .resize(0,h) 

    I have never tried and am not sure that it changes the size of a placeholder, but I know for sure that it changes the size of the loaded image.

    In this case, I would recommend in the placeholder to transfer the Drawable desired size, for example:

     Bitmap bitmap = Bitmap.createBitmap(widthPx, heightPx, Bitmap.Config.ARGB_8888) Canvas canvas = new Canvas(); canvas.drawColor(Color.LTGRAY) drawable = new BitmapDrawable(context, bitmap); 

    If the size of all images is the same, then it is better to do such a drawable initialization once and put it into a separate method.

    If the images are often the same size, it is better to make a cache with drawable for placeHolders, and the Canvas is better to make a final static field of the class, otherwise in a large list you will encounter such a problem as a garbage collector, which will be noticeable as hanging.

    If all the images are always different and they are very, very much, then you better think about one instance of the size-averaged drawable for placeholdera.

    • I knew that I needed to dig in the direction of Drawable for a placeholder. I'll try now :) - Flippy