Pages

getteammates.com

Tuesday, 22 December 2015

Event handling and add, remove and change operations in Android RecyclerView

It is highly recommended that you go through the earlier post on RecyclerView, please click here to go to there.

We will create a simple layout file with RecyclerView and radio buttons to select the operations

Creating the layout file.

Layout file is shown below, lets name it as main2.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/alphaList"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical" />

    <RadioGroup
        android:id="@+id/opGroup"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <RadioButton
            android:id="@+id/opAdd"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Add"
            android:checked="true"/>
        <RadioButton
            android:id="@+id/opRemove"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Remove"
            android:checked="false"/>
        <RadioButton
            android:id="@+id/opChange"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Change"
            android:checked="false"/>
    </RadioGroup>

</RelativeLayout>

Create one more layout file to represent a row in the RecyclerView. Let us name the file as fruit.xml.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/fruitNameText"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="@android:color/holo_blue_light"
        android:layout_margin="1dp"
        android:text="name"/>

    <TextView
        android:id="@+id/vitaminCText"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="@android:color/holo_blue_light"
        android:layout_margin="1dp"
        android:text="description"/>

</LinearLayout>


In our example we will have fruit and its vitamin C content as a list.

Lets create a simple class to store the values.
package com.example.recycleviewexample;

public class FruitData {
    public String mName;
    public String mVitaminC;

    public FruitData(String n, String d) {
        mName = n;
        mVitaminC = d;
    }

    // These data represent the initial data the the RecyclerView will have
    // These are just sample data
    static final FruitData[] getList1() {
        return new FruitData[] {
                new FruitData("Apricots", "5000"),
                new FruitData("Apple", "5000"),
                new FruitData("Banana", "10.000"),
                new FruitData("Blackberries", "150.000"),
                new FruitData("Cherries", "10.000"),
                new FruitData("Grapefruit", "40.000"),
                new FruitData("Grapes", "3000")
        };
    }

    // These data will be added/changed when the user select the corresponding operations
    static final FruitData[] getList2() {
        return new FruitData[] {
                new FruitData("Kiwi", "70.000"),
                new FruitData("Lemon", "40.000"),
                new FruitData("Lychee", "23.000"),
                new FruitData("Mango", "23.000"),
                new FruitData("Orange", "49.000"),
                new FruitData("Peach", "7000"),
                new FruitData("Pear", "4000"),
                new FruitData("Pineapple", "25.000"),
                new FruitData("Plum", "5000"),
                new FruitData("Pumpkin", "16.000"),
                new FruitData("Raspberries", "5000")
        };
    }
}

Adapter and View holder

package com.example.recycleviewexample;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;

// An implementation of the RecyclerView.Adapter with ClickableFruitAdapter.ViewHolder as ViewHolder
public class ClickableFruitAdapter extends RecyclerView.Adapter<ClickableFruitAdapter.ViewHolder> {

    // Upon click event mListener.onClicked(int pos) will be raised
    private FruitItemClickedListener mListener;

    // View holder, it will have views for fruitNameText(fruit name) and vitaminCText(vitamin C content). 
    public class ViewHolder extends RecyclerView.ViewHolder {
        public TextView mNameText;
        public TextView mVitaminCText;

 // In the constructor we will assign the views
        public ViewHolder(View v) {
            super(v);
            mNameText = (TextView) v.findViewById(R.id.fruitNameText);
            mVitaminCText = (TextView) v.findViewById(R.id.vitaminCText);
        }
    }

    private ArrayList<FruitData> mFruits = new ArrayList<FruitData>();

    public ClickableFruitAdapter(FruitData[] desc, FruitItemClickedListener l) {
        for (FruitData d: desc) {
            mFruits.add(d);
        }
        mListener = l;
    }

    // Add a fruit to the RecyclerView
    public void addFruit(int pos, FruitData data) {
        mFruits.add(pos, data);
        notifyItemInserted(pos);
    }

    // Remove a fruit from the RecyclerView
    public FruitData removeFruit(int pos) {
        FruitData d = mFruits.get(pos);
        mFruits.remove(pos);
        notifyItemRemoved(pos);
        return d;
    }

     // Change a fruit in the RecyclerView
    public FruitData changeFruit(int pos, FruitData data) {
        FruitData d = mFruits.get(pos);
        mFruits.set(pos, data);
        notifyItemChanged(pos);
        return d;
    }

    // In this method we should create a row for our RecyclerView
    // and return an instance of ViewHolder
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit, parent, false);
        return new ViewHolder(v);
    }

    public static class NameClickListener implements View.OnClickListener {

        private ViewHolder mHolder;
        private FruitItemClickedListener mListener;

        public NameClickListener(ViewHolder holder, FruitItemClickedListener listener) {
            mHolder = holder;
            mListener = listener;
        }

        @Override
        public void onClick(View view) {
            if (mHolder.getLayoutPosition() >= 0) {
                // Raise the onClicked event after getting the position using getLayoutPosition() method,
  // You can also use getAdapterPosition () method to retrieve the position
  // getLayoutPosition()  returns the position of the ViewHolder in terms of the latest layout pass.
  // getAdapterPosition() returns the Adapter position of the item represented by this ViewHolder.
  // getAdapterPosition() might be different than the getLayoutPosition() if there are pending adapter updates but a new layout pass has not happened yet.
                mListener.onClicked(mHolder.getLayoutPosition());
            }
        }
    }

    // Assign the values for the ViewHolder
    // This method can be called when we have to assign a newly created row or when recycling is required.
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        final FruitData fruit = mFruits.get(position);
        holder.mNameText.setText(fruit.mName);
        holder.mVitaminCText.setText(fruit.mVitaminC);

 // Set click listener for the view
        holder.itemView.setOnClickListener(new NameClickListener(holder, mListener));
    }

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

The listener class
package com.example.recycleviewexample;

public interface FruitItemClickedListener {

    void onClicked(int pos);
}

The Activity implementation

Now we have almost everything ready, lets put everything together in our Activity implementation.
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import android.os.Bundle;
import android.util.Log;
import android.widget.RadioGroup;

import java.util.ArrayList;

public class RecyclerItemOperationActivity extends AppCompatActivity implements FruitItemClickedListener {
    protected RecyclerView mRecyclerView;
    protected RecyclerView.LayoutManager mLayoutManager;

    protected ArrayList<fruitdata> mExtraFruits = new ArrayList<fruitdata>();
    protected ClickableFruitAdapter mAdapter;
    protected int mMode = R.id.opAdd;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main2);

        mRecyclerView  = (RecyclerView)findViewById(R.id.alphaList);
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        mAdapter = new ClickableFruitAdapter(FruitData.getList1(), this);
        mRecyclerView.setAdapter(mAdapter);

        for (FruitData d: FruitData.getList2()) {
            mExtraFruits.add(d);
        }

        RadioGroup opGroup = (RadioGroup)findViewById(R.id.opGroup);
        opGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, int i) {
                mMode = i;
            }
        });

    }

    @Override
    public void onClicked(int pos) {
        if (mMode == R.id.opAdd) {
            if (mExtraFruits.size() > 0) {
                mAdapter.addFruit(pos, mExtraFruits.get(0));
                mExtraFruits.remove(0);
            }
        } else if (mMode == R.id.opRemove) {
            mExtraFruits.add(mAdapter.removeFruit(pos));
        } else if (mMode == R.id.opChange) {
            if (mExtraFruits.size() > 0) {
                FruitData d = mExtraFruits.get(0);
                mExtraFruits.add(mAdapter.changeFruit(pos, d));
                mExtraFruits.remove(0);
                mExtraFruits.add(d);
            }
        }
    }
}


No comments:

Post a Comment