我有一个 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;
}
});
有谁知道出了什么问题?
提前致谢,