滚动StaggeredGridLayout

时间:2016-01-27 21:26:57

标签: android android-recyclerview picasso staggered-gridview

我有一个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;
            }
        });

有没有人知道什么是错的?

提前致谢,

1 个答案:

答案 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);
            }
        };