Axel
Axel

Reputation: 1674

Is there any widget that replaces the deprecated Gallery widget

I need to implement in my app some sort of horizontal ListViews so that after a user selects an item from the first ListView (Categories), then the second ListView displays all items related to that selected item(Products in a category).

I was planning to use the Gallery widget but since it's been deprecated, I tried to find a good replacement, but with no luck.

This is what I found:

  1. Solution using ViewPager (See the CommonsWare's answer) : Kind of complicated and with no example of how to handle a simple click event.
  2. Solution using a third-party library that implements a Horizontal ListView : Sound good, but not being an official widget makes me wonder if it's the right way to go.
  3. Solution using a third-party library that implements a very nice gallery with a cover flow effect: Same problem than the second solution.

You see, the main problem is that I've already developed a couple of apps without the need of using any third-party library, and I wouldn't like to use one unless it is really necessary.

For that reason I want to ask you guys, if you know of any solution/approach that combines:

enter image description here

EDIT:

Following @Ewoks and @CommonsWare's advice I give the RecyclerView a try and it turned out to be what I need and not as complicated as I thought it'd be.

Here's the links I used, in case someone may find them useful:

With a few changes I made to the example of the second link I managed to get the two galleries I needed in which the second gallery listed all the dishes in the category selected in the first gallery.

Here's the result:

enter image description here

As I said, getting that result wasn't that difficult, I only have to indicate a HORIZONTAL orientation in the constructor of the LinearLayoutManager

mCategoryHorizontalManager=new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false);

Also I didn't use Picasso, I used Ion because in my project I also need to handle HTTP requests and Picasso only works with images.

Well my problem now, as you can tell, is not how display images, but how to make the clicked item have a special style (a frame, border, background colour), something that make it very clear which item was selected.

So far, I think I managed to somehow change the style of selected item, but I'm not happy with it. You can see the result in the image above, where the selected item has a different background colour (CYAN) :

This is the layout for each item of my RecyclerView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="10dp"
    android:gravity="center"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/picture_image_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp" />

    <TextView
        android:id="@+id/desc_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

And here's my Adapter:

public class GalleryItemAdapter extends RecyclerView.Adapter<GalleryItemAdapter.ItemHolder>{

    /**
     * Click handler interface. RecyclerView does not have
     * its own built in like AdapterView do.
     */
    public interface OnItemClickListener{
        public void onItemClick(ItemHolder item, int position);
    }

    private List<GalleryObject> mItems;

    private OnItemClickListener mOnItemClickListener;
    private LayoutInflater mLayoutInflater;
    
    private View mSelectedView; 

    public GalleryItemAdapter(Context context,List<GalleryObject> picsList,int level){
        //...
        mSelectedView=null; //There's no selected item at first
    }

    @Override
    public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView=mLayoutInflater.inflate(R.layout.recycler_row, parent,false);

        return new ItemHolder(itemView,this);

    }

    @Override
    public void onBindViewHolder(ItemHolder holder, int position) {
        holder.setTituloTextView(mItems.get(position).getImageTitle());
        Ion.with(holder.getPicImageView())
                .placeholder(R.mipmap.owner_placeholder)
                .resize(mSize,mSize)
                .centerCrop()
                .error(R.mipmap.owner_error)
                .load(mItems.get(position).getImageUrl());

    }

    @Override
    public int getItemCount() {
        return mItems.size();
    }

    public OnItemClickListener getOnItemClickListener() {
        return this.mOnItemClickListener;
    }

    public void setOnItemClickListener(OnItemClickListener listener) {
        this.mOnItemClickListener = listener;
    }

    /* To highlight selected item*/

    public View getSelectedView() {
        return mSelectedView;
    }

    public void setSelectedView(View selectedView) {
        this.mSelectedView = selectedView;
    }

    /* Required implementation of ViewHolder to wrap item view */
    public static class ItemHolder extends RecyclerView.ViewHolder implements
        View.OnClickListener{
        private GalleryItemAdapter mParent;
        private TextView mTituloTextView;
        private ImageView mPicImageView;
        public ItemHolder(View itemView, GalleryItemAdapter parent) {
            super(itemView);
            itemView.setOnClickListener(this);

            mParent=parent;

            mTituloTextView= (TextView) itemView.findViewById(R.id.desc_text_view);
            mPicImageView= (ImageView) itemView.findViewById(R.id.picture_image_view);
        }

        public void setTituloTextView(CharSequence titulo) {
            this.mTituloTextView.setText(titulo);
        }

        public ImageView getPicImageView() {
            return mPicImageView;
        }
        public CharSequence getImageText(){
            return mTituloTextView.getText();
        }
        public int getGalleryLevel(){
            return mParent.mLevel;
        }

        @Override
        public void onClick(View v) {
            final OnItemClickListener listener=mParent.getOnItemClickListener();
            if(listener!=null){
                listener.onItemClick(this,getPosition());
            }
            setItemActivated(v);
        }
        public void setItemActivated(View v){
            if(mParent.getSelectedView()!=null){
               mParent.getSelectedView().setBackgroundColor(Color.TRANSPARENT);
            }
            v.setBackgroundColor(Color.CYAN);
            mParent.setSelectedView(v);
        }
    }
}

As you can see, whenever the uses clicks on a item I call setItemActivated, in which I checked if the mSelectedView is not null (a item was selected previously) using the getter getSelectedView(), in which case, I change the background colour back to TRANSPARENT.

Regardless of the value of mSelectedView, I change the background colour of the current view to CYAN:

v.setBackgroundColor(Color.CYAN);

And finally update mSelectedView with the current selected item:

mParent.setSelectedView(v);

This works, but the result is awful as it changes the background of the whole view, when I think only the image should somehow be highlighted.

Do you know how I can change the style of the image in a nicer way? Perhaps there's a out of the box solution for highlighting the selected item that I don't know of.

Thank you very much.

Upvotes: 0

Views: 1535

Answers (1)

Ewoks
Ewoks

Reputation: 12445

RecyclerView with his build-in LayoutManagers of which I would recommend you GridLayout which suits gallery purpose the best. In case you do not like that you can always implement your own LayoutManager by extending RecyclerView.LayoutManager

I hope this helps enough as some initial guide... ;)

p.s. i would certainly not recommend CoverFlow because all other mentioned classes offers richer APIs. Additionally its implementation lacks a lot of on performance matter.

Upvotes: 2

Related Questions