Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call transition animation from RecyclerView Adapter instead of Activity

I have an app with a RecyclerView filled with some cards, with help of a custom RecyclerView (RV) Adapter I made. I then tried to follow this tutorial in order to add a transition between activities. However, as shown in the tutorial, the animations are called when creating an Intent inside an Activity, and my OnClick code is inside the RVAdapter. This gives me no access to the Activity required on the method

Intent intent = new Intent(HomeActivity.this, TargetActivity.class);
intent.putExtra(TargetActivity.ID, Contact.CONTACTS[position].getId());
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
        // the context of the activity
        MainActivity.this,

        // For each shared element, add to this method a new Pair item,
        // which contains the reference of the view we are transitioning *from*,
        // and the value of the transitionName attribute
        new Pair<View, String>(view.findViewById(R.id.CONTACT_circle),
                getString(R.string.transition_name_circle)),
        new Pair<View, String>(view.findViewById(R.id.CONTACT_name),
                getString(R.string.transition_name_name)),
        new Pair<View, String>(view.findViewById(R.id.CONTACT_phone),
                getString(R.string.transition_name_phone))
);
ActivityCompat.startActivity(HomeActivity.this, intent, options.toBundle());

I tried to pass the Activity Object to the RVAdapter in its constructor method, but it only resulted in NullPointerExceptions.

Here's my RVAdapter code:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.AppVH>{


ArrayList<App> apps;

@Override
public AppVH onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
    return new AppVH(v);
}

@Override
public void onBindViewHolder(AppVH holder, int position) {
    holder.name.setText(apps.get(position).getName());
    holder.artist.setText(apps.get(position).getArtist());
    String p = "";
    if(apps.get(position).getPrice()==0.0) p="Free";
    else p= "$"+apps.get(position).getPrice()+" "+apps.get(position).getCurrency();
    holder.price.setText(p);
    Picasso.with(AppListActivity.context).load(apps.get(position).getUrlImLarge()).into(holder.icon);
}

@Override
public int getItemCount() {
    return apps.size();
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);
}

RecyclerViewAdapter(ArrayList<App> applications){
    this.apps = applications;
}

// Clean all elements of the recycler
public void clear() {
    apps.clear();
    notifyDataSetChanged();
}

// Add a list of items
public void addAll(ArrayList<App> list) {
    apps.addAll(list);
    notifyDataSetChanged();
}

public class AppVH extends RecyclerView.ViewHolder implements View.OnClickListener{

    CardView cv;
    TextView name;
    TextView artist;
    TextView price;
    ImageView icon;
    private final Context c;

    public AppVH(View itemView) {
        super(itemView);
        cv = (CardView) itemView.findViewById(R.id.cardview);
        name = (TextView) itemView.findViewById(R.id.app_name);
        artist = (TextView) itemView.findViewById(R.id.app_artist);
        price = (TextView) itemView.findViewById(R.id.app_price);
        icon = (ImageView) itemView.findViewById(R.id.app_icon);
        itemView.setOnClickListener(this);
        c = itemView.getContext();
    }

    @Override
    public void onClick(View v) {
        final Intent intent;
        Log.d("Debugtext","Card with position " + getAdapterPosition() + " was touched.");
        intent = new Intent(c, AppDetailActivity.class);
        intent.putExtra("app",apps.get(getAdapterPosition()));
        c.startActivity(intent);
    }
}
}

Here's how I add the adapter to the RecyclerView in my "HomeActivity".

RecyclerView rv = (RecyclerView) findViewById(R.id.recycler_view);

    rv.setHasFixedSize(true);
    GridLayoutManager gridlm = new GridLayoutManager(getApplicationContext(),columns);
    rv.setLayoutManager(gridlm);
    rvadapter = new RecyclerViewAdapter(apps);
    rv.setAdapter(rvadapter);

Is there an easy way to call the ActivityCompat.startActivity(...) method from within the Adapter?

like image 305
Hugo M. Zuleta Avatar asked Feb 07 '16 19:02

Hugo M. Zuleta


2 Answers

So, I did a very simple thing: I casted the context as an activity. Wow.

        @Override
        public void onClick(View v) {
            final Intent intent;
            //Opens the AppDetailActivity showing the selected App Card
            //Log.d("Debugtext","Card with position " + getAdapterPosition() + " was touched.");
            intent = new Intent(c, AppDetailActivity.class);
            intent.putExtra("app",apps.get(getAdapterPosition()));

            ActivityOptionsCompat options = ActivityOptionsCompat.
                    makeSceneTransitionAnimation((Activity)c, (View)cv, "appcard");
            c.startActivity(intent, options.toBundle());
        }
like image 125
Hugo M. Zuleta Avatar answered Sep 20 '22 16:09

Hugo M. Zuleta


ActivityOptions options  = ActivityOptions.makeSceneTransitionAnimation((Activity) mContext);

Note: mContext was initialized in the recycler adapter constructor.

like image 22
Bukunmi Avatar answered Sep 24 '22 16:09

Bukunmi