我有一个RecyclerView来显示毕加索加载的一些图像。由于它们具有不同的宽高比,我使用的是StaggeredGridLayoutManager。一切看起来都不错,但是当滚动并显示新图像时,图像会向上或向下移动一点,就像它们被重新定位一样。他们不会待在同一个地方。
问题是,如果我使用GridLayout,一切都很完美,看起来有不同的项目大小搞砸了。
这是ActivityMain类:
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Especificamos el layout 'products_grid.xml'
setContentView(R.layout.products_grid);
_initData();
_initAuxViews();
_initToolbar();
_initNavigationDrawers();
_initAnimations();
new ConnectToServer().execute();
}
protected void _initRecyclerView()
{
mProductsRecyclerView = (RecyclerView)findViewById(R.id.grid_recycler);
mStaggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
mProductAdapter = new ProductsGridAdapter(this, mProductsDisplayedList);
mProductsRecyclerView.setLayoutManager(mStaggeredGridLayoutManager);
mProductsRecyclerView.setAdapter(mProductAdapter);
mProductsRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener()
{
...
}
}
main.xml,我有一个自定义的RecyclerView,但这不影响,我查了一下。
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/shop_background_bw">
<!-- Contenido principal -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Recylcer Grid -->
<com.wallakoala.wallakoala.Views.GridRecyclerView
android:id="@+id/grid_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
android:clipToPadding="false"
android:paddingTop="?attr/actionBarSize"
android:layoutAnimation="@anim/grid_layout_animation"/>
<!-- Toolbar -->
<include android:id="@+id/appbar"
layout="@layout/toolbar">
</include>
<!-- Loading View -->
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/avloadingIndicatorView"
android:layout_width="125dp"
android:layout_height="125dp"
android:layout_gravity="center"
android:visibility="gone"
app:indicator="BallClipRotate"
app:indicator_color="@color/colorAccent"/>
<!-- Texto de no prductos -->
<TextView
android:id="@+id/nodata_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/action_bar_height"
android:layout_gravity="center_horizontal"
android:visibility="gone"
android:paddingTop="@dimen/action_bar_height"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/nodata_message"
android:textSize="20sp"
android:textColor="@color/colorText"/>
</FrameLayout>
<include layout="@layout/left_navigation_drawer"/>
</android.support.v4.widget.DrawerLayout>
</android.support.design.widget.CoordinatorLayout>
item_grid.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_item"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardPreventCornerOverlap="false"
app:cardElevation="4dp"
app:cardCornerRadius="4dp"
app:cardUseCompatPadding="true">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Loading View -->
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/avloadingitem"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:visibility="gone"
app:indicator="BallClipRotate"
app:indicator_color="@color/colorAccent"/>
<!-- Background-->
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/grid_background"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@color/colorText"
android:alpha="0.2"
android:visibility="gone"
app:riv_corner_radius_bottom_left="4dp"
app:riv_corner_radius_bottom_right="4dp"
app:riv_corner_radius_top_left="4dp"
app:riv_corner_radius_top_right="4dp"/>
<!-- Main Image-->
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/grid_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
app:riv_corner_radius_bottom_left="4dp"
app:riv_corner_radius_bottom_right="4dp"
app:riv_corner_radius_top_left="4dp"
app:riv_corner_radius_top_right="4dp"/>
<!-- Footer -->
<RelativeLayout
android:id="@+id/footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:alpha="0.75">
<!-- Info extra -->
<include android:id="@+id/extraInfo"
layout="@layout/product_footer_extra"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible"/>
<!-- Info principal -->
<include android:id="@+id/mainFooter"
layout="@layout/product_footer"
android:layout_height="@dimen/footer_height"
android:layout_width="match_parent"
android:layout_below="@id/extraInfo"/>
</RelativeLayout>
</FrameLayout>
</android.support.v7.widget.CardView>
编辑:适配器代码:
public class ProductsGridAdapter extends RecyclerView.Adapter<ProductsGridAdapter.ProductHolder>
{
/* Constants */
private static final String TAG = "CUOKA";
private static final String PACKAGE = "com.wallakoala.wallakoala";
/* Context */
private static Context mContext;
/* Data */
private static List<Product> mProductList;
public static class ProductHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
private Product mProduct;
private ImageButton mFavImageButton;
private ImageView mProductImageView;
private ImageView mErrorImageView;
private View mLoadingView;
private View mBackgroundView;
private View mProductFooterView, mProductFooterExtraView, mProductFooterMainView;
private TextView mTitleTextView, mSubtitleTextView, mNameTextView, mPriceTextView;
private Animation scaleUpFooterExtra, scaleDownFooterExtra;
public ProductHolder(View itemView)
{
super(itemView);
mErrorImageView = (ImageView)itemView.findViewById(R.id.broken_image);
mTitleTextView = (TextView)itemView.findViewById(R.id.footer_title);
mSubtitleTextView = (TextView)itemView.findViewById(R.id.footer_subtitle);
mProductImageView = (ImageView)itemView.findViewById(R.id.grid_image);
mFavImageButton = (ImageButton)itemView.findViewById(R.id.footer_fav_button);
mNameTextView = (TextView)itemView.findViewById(R.id.name);
mPriceTextView = (TextView)itemView.findViewById(R.id.price);
mBackgroundView = itemView.findViewById(R.id.grid_background);
mLoadingView = itemView.findViewById(R.id.avloadingitem);
mProductFooterView = itemView.findViewById(R.id.footer);
mProductFooterExtraView = itemView.findViewById(R.id.extraInfo);
mProductFooterMainView = itemView.findViewById(R.id.mainFooter);
mProductFooterView.setOnClickListener(this);
//mProductImageView.setOnClickListener(this);
scaleUpFooterExtra = AnimationUtils.loadAnimation(mContext, R.anim.scale_up);
scaleDownFooterExtra = AnimationUtils.loadAnimation(mContext, R.anim.scale_down);
}
public void bindProduct(Product product)
{
/* Inicializamos los TextViews */
mTitleTextView.setText(product.getShop());
mSubtitleTextView.setText(product.getColors().get(0).getReference());
mNameTextView.setText(product.getName());
mPriceTextView.setText(String.format("%.2f", product.getPrice()) + "€");
/* Ocultamos la info, IMPORTANTE. Cosas malas pasan si no se pone. Tambien la imagen de error. */
mProductFooterExtraView.setVisibility(View.GONE);
mProductFooterMainView.setVisibility(View.GONE);
mErrorImageView.setVisibility(View.GONE);
/* Mostramos la view de carga y el background */
mLoadingView.setVisibility(View.VISIBLE);
mBackgroundView.setVisibility(View.VISIBLE);
/* Ponemos el icono del corazon. */
mFavImageButton.setBackgroundResource(R.drawable.ic_favorite_border_white);
/* Cargamos la imagen usando Picasso */
String url = product.getColors().get(0).getImages().get(0).getPath().replaceAll(".jpg", "_Small.jpg");
Picasso.with(mContext)
.load(url)
.into(mProductImageView, new Callback() {
@Override
public void onSuccess() {
mBackgroundView.setVisibility(View.GONE);
mLoadingView.setVisibility(View.GONE);
mProductFooterMainView.setVisibility(View.VISIBLE);
}
@Override
public void onError() {
mLoadingView.setVisibility(View.GONE);
mErrorImageView.setVisibility(View.VISIBLE);
}
});
mProduct = product;
}
public ProductsGridAdapter(Context context, List<Product> productList)
{
mContext = context;
mProductList = productList;
}
public void updateProductList(List<Product> productList)
{
mProductList = productList;
}
@Override
public ProductHolder onCreateViewHolder(ViewGroup viewGroup, int viewType)
{
View itemView = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.product_item_grid
, viewGroup
, false );
return new ProductHolder(itemView);
}
@Override
public void onBindViewHolder(final ProductHolder productHolder, int pos)
{
productHolder.bindProduct(mProductList.get(pos));
}
@Override
public int getItemCount()
{
return mProductList.size();
}
}
编辑2 :我发现了正在发生的事情。首先在没有图像的情况下创建cardview,当它被加载时,布局被重新绘制,因此产生了奇怪的运动。我试着这样做:
首次加载图像时,我保存图像的高度,当向上滚动recyclerView时,我设置了cardview的背景图像,其高度已经保存,因此它与图像的尺寸相同,这个应该做的伎俩。但它没有。这就是我尝试过的,这段代码属于Adapter中的Holder构造函数。
final ViewTreeObserver mProductImageViewTreeObserver = mProductImageView.getViewTreeObserver();
final ViewTreeObserver mBackgroundTreeObserver = mBackgroundView.getViewTreeObserver();
mProductImageViewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout()
{
if (mProductHeight != mProductImageView.getHeight())
{
mProductHeight = mProductImageView.getHeight();
}
}
});
mBackgroundTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
{
@Override
public boolean onPreDraw()
{
if((mProductHeight > 0) && (mProductHeight != mBackgroundView.getHeight()))
{
mBackgroundView.getLayoutParams().height = mProductHeight;
}
return true;
}
});
有没有人知道什么是错的?
提前致谢,
答案 0 :(得分:0)
我自己找到了解决方案。诀窍是在第一次将图像加载到Target对象时保存纵横比。
然后,在OnPrepareLoad中,检查此图像是否先前已加载。如果是这样,使用存储的宽高比来设置最终高度,这样就没有重新调整,滚动也能顺利进行。
mTarget = new Target()
{
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from)
{
mLoadingView.setVisibility(View.GONE);
mProductFooterMainView.setVisibility(View.VISIBLE);
mProductImageView.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
mProductImageView.setBackgroundColor(-1);
mProductImageView.setAlpha(1.0f);
if (mProductBitmapArray[position] == 0.0f)
mProductBitmapArray[position] = (double)bitmap.getHeight() / (double)bitmap.getWidth();
mProductImageView.setImageBitmap(bitmap);
}
@Override
public void onBitmapFailed(Drawable errorDrawable)
{
... do stuff
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable)
{
mProductImageView.setImageBitmap(null);
if (mProductBitmapArray[position] != 0)
mProductImageView.getLayoutParams().height = (int)(mProductImageView.getWidth()
* mProductBitmapArray[position]);
else
mProductImageView.getLayoutParams().height = 600;
mProductImageView.setBackgroundColor(mContext.getResources().getColor(R.color.colorText));
mProductImageView.setAlpha(0.1f);
}
};