Saturday, 3 December 2016

RecyclerView fast scroll in android


RecyclerView is major used in building any awesome app. In my last article I have discussed about the swipe and delete item of recyclerView. If you have n't seen then Please check here Swipe to delete item of recyclerview.

RecyclerView provides better in term of scrolling any complex items. Now days people are using very complex layout and design of long list. And very difficult to scroll to find a particular item while scrolling. To over come this issue RecyclerView provides the fast scroll. You can find item very easy while scrolling.

Here in this article I am sharing one awesome library that helps you to make this in very simple way.
He made our life very easy and simple. Please give full credit to original author. Here is the Github link.  So lets implement this library in our simple project. Before proceed please check this  video that helps you what are going to implements.


Lets create an android project RecyclerView Fast scroll. Here is added all my dependencies.

build.gradle app level

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.0"
    defaultConfig {
        applicationId "com.sunil.recyclerviewfastscroll"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.0.0'
    testCompile 'junit:junit:4.12'

    compile 'com.android.support:recyclerview-v7:25.0.0'
    compile 'com.android.support:cardview-v7:25.0.0'
    compile 'com.android.support:design:25.0.0'

    compile 'com.jakewharton:butterknife:8.4.0'
    apt 'com.jakewharton:butterknife-compiler:8.4.0'

    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'de.hdodenhof:circleimageview:2.0.0'
    compile 'com.simplecityapps:recyclerview-fastscroll:1.0.11'
    
}

ItemModel.java

public class ItemModel {

    private String name;
    private String imagePath;

    public ItemModel(){

    }

    public ItemModel(String name, String imagePath) {
        this.name = name;
        this.imagePath = imagePath;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getImagePath() {
        return imagePath;
    }

    public void setImagePath(String imagePath) {
        this.imagePath = imagePath;
    }
}

ItemModel.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;

public class MainActivity extends AppCompatActivity {

    private final static String TAG = MainActivity.class.getSimpleName();

    private String[] names = Constant.name;
    private  String[] images = Constant.image;

    private RecyclerItemAdapter mAdapter;

    @BindView(R.id.recyclerView)
    RecyclerView recyclerView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        initView();

    }
    private void initView() {
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        List listItems = getList();
        mAdapter = new RecyclerItemAdapter(this, listItems);
        recyclerView.setAdapter(mAdapter);
        recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));

    }

    private List getList(){
        List list = new ArrayList<>();
        for (int index =0; index < names.length; index++){
            ItemModel itemModel = new ItemModel();
            itemModel.setName(names[index]);
            itemModel.setImagePath(images[index]);
            list.add(itemModel);
        }

        if (list.size() > 0) {
            Collections.sort(list, new Comparator() {
                @Override
                public int compare(final ItemModel object1, final ItemModel object2) {
                    return object1.getName().compareTo(object2.getName());
                }
            });
        }
        return list;
    }
}

activity_main.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"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.sunil.recyclerviewfastscroll.MainActivity">

    <com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:fastScrollPopupBgColor="@color/colorAccent"
        app:fastScrollPopupTextColor="@android:color/primary_text_dark"
        app:fastScrollThumbColor="@color/colorAccent">
    </com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView>


<</RelativeLayout>

RecyclerItemAdapter.java

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;

import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * Created by sunil on 12/3/16.
 */

public class RecyclerItemAdapter extends RecyclerView.Adapter implements FastScrollRecyclerView.SectionedAdapter {

    private List itemModels;
    private Context context;

    public RecyclerItemAdapter(Context context, List wallTalls) {
        this.itemModels = wallTalls;
        this.context = context;
    }

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


    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_layout, viewGroup, false);
        return new ItemViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        ItemModel model = itemModels.get(position);
        initializeViews(model, holder, position);
    }


    private void initializeViews(ItemModel model, final RecyclerView.ViewHolder holder, int position) {

        String imageUrl = model.getImagePath();
        if (imageUrl != null && !imageUrl.isEmpty()){
            Glide.with(context)
                    .load(imageUrl)
                    .into(((ItemViewHolder)holder).imageView);

            }
            ((ItemViewHolder)holder).name.setText(model.getName());
        }

        @NonNull
        @Override
        public String getSectionName(int position) {
            return Character.toString(itemModels.get(position).getName().charAt(0));
    }

    public static class ItemViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.name)
        TextView name;
        @BindView(R.id.imageView)
        ImageView imageView;

        public ItemViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }


}

item_layout.xml

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

   <de.hdodenhof.circleimageview.CircleImageView
        android:src="@mipmap/ic_launcher"
        android:id="@+id/imageView"
        android:layout_width="70dp"
        android:layout_height="70dp" />

    <TextView
        android:id="@+id/name"
        android:text="name"
        android:textStyle="bold"
        android:layout_alignBaseline="@id/imageView"
        android:layout_margin="10dp"
        android:gravity="center_vertical"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_toRightOf="@+id/imageView"/>

</RelativeLayout>

Here is the snap shot.

Thanks for reading this post. I hope this post will help you to understand.

Thursday, 1 December 2016

Swipe to Delete Item of RecyclerView in Android


In the last article we have learned about how to expand and collapse item of the recyclerView. If you have not seen please check with this link Expandable item in recyclerview.

Today I am focusing good feature about swipe to delete or add item in recyclerView because it is good user experience.  In recyclerView provide ItemHelper Class to handle this case. But it not provide good customized.

While searching the best feature I found one library That really help me. He made our life easy, so full credit goes to him, For more details about this library Here is detail link: Itemtouchhelper-extension

In this article We can swipe three different way to delete the item of recyclerView.

1. Swipe with Item width Spring
2. Swipe with Item width no Spring
3. Swipe with Item width.

You can see the detail in this uploaded video. It will helps you to understand the behavior.

Lets focus about to implements this library to our android project, It very simple just add the dependency to our project to used to same class to make more customized things.


build.gradle app level

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.0"
    defaultConfig {
        applicationId "com.sunil.swipedeleteitemrecyclervieew"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.0.0'
    testCompile 'junit:junit:4.12'

    compile 'com.android.support:recyclerview-v7:25.0.0'
    compile 'com.android.support:cardview-v7:25.0.0'
    compile 'com.android.support:design:25.0.0'

    compile 'com.jakewharton:butterknife:8.4.0'
    apt 'com.jakewharton:butterknife-compiler:8.4.0'

    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'de.hdodenhof:circleimageview:2.0.0'
}

ItemTouchUIUtilImpl.java

class ItemTouchUIUtilImpl {
    static class Lollipop extends Honeycomb {
        @Override
        public void onDraw(Canvas c, RecyclerView recyclerView, View view,
                           float dX, float dY, int actionState, boolean isCurrentlyActive) {
            if (isCurrentlyActive) {
                Object originalElevation = view.getTag(R.id.item_touch_helper_previous_elevation);
                if (originalElevation == null) {
                    originalElevation = ViewCompat.getElevation(view);
                    float newElevation = 1f + findMaxElevation(recyclerView, view);
                    ViewCompat.setElevation(view, newElevation);
                    view.setTag(R.id.item_touch_helper_previous_elevation, originalElevation);
                }
            }
            super.onDraw(c, recyclerView, view, dX, dY, actionState, isCurrentlyActive);
        }

        private float findMaxElevation(RecyclerView recyclerView, View itemView) {
            final int childCount = recyclerView.getChildCount();
            float max = 0;
            for (int i = 0; i < childCount; i++) {
                final View child = recyclerView.getChildAt(i);
                if (child == itemView) {
                    continue;
                }
                final float elevation = ViewCompat.getElevation(child);
                if (elevation > max) {
                    max = elevation;
                }
            }
            return max;
        }

        @Override
        public void clearView(View view) {
            final Object tag = view.getTag(R.id.item_touch_helper_previous_elevation);
            if (tag != null && tag instanceof Float) {
                ViewCompat.setElevation(view, (Float) tag);
            }
            view.setTag(R.id.item_touch_helper_previous_elevation, null);
            super.clearView(view);
        }
    }

    static class Honeycomb implements ItemTouchUIUtil {

        @Override
        public void clearView(View view) {
            ViewCompat.setTranslationX(view, 0f);
            ViewCompat.setTranslationY(view, 0f);
        }

        @Override
        public void onSelected(View view) {

        }

        @Override
        public void onDraw(Canvas c, RecyclerView recyclerView, View view,
                           float dX, float dY, int actionState, boolean isCurrentlyActive) {
            ViewCompat.setTranslationX(view, dX);
            ViewCompat.setTranslationY(view, dY);
        }

        @Override
        public void onDrawOver(Canvas c, RecyclerView recyclerView,
                               View view, float dX, float dY, int actionState, boolean isCurrentlyActive) {

        }
    }

    static class Gingerbread implements ItemTouchUIUtil {

        private void draw(Canvas c, RecyclerView parent, View view,
                          float dX, float dY) {
            c.save();
            c.translate(dX, dY);
            parent.drawChild(c, view, 0);
            c.restore();
        }

        @Override
        public void clearView(View view) {
            view.setVisibility(View.VISIBLE);
        }

        @Override
        public void onSelected(View view) {
            view.setVisibility(View.INVISIBLE);
        }

        @Override
        public void onDraw(Canvas c, RecyclerView recyclerView, View view,
                           float dX, float dY, int actionState, boolean isCurrentlyActive) {
            if (actionState != ItemTouchHelper.ACTION_STATE_DRAG) {
                draw(c, recyclerView, view, dX, dY);
            }
        }

        @Override
        public void onDrawOver(Canvas c, RecyclerView recyclerView,
                               View view, float dX, float dY,
                               int actionState, boolean isCurrentlyActive) {
            if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
                draw(c, recyclerView, view, dX, dY);
            }
        }
    }
}

MainActivity.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import java.util.ArrayList;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;

public class MainActivity extends AppCompatActivity {

    String imageUrl[] = Constant.image;
    String names[] = Constant.name;
    RecyclerAdapter adapter;

    @BindView(R.id.recyclerView)
    RecyclerView recyclerView;

    public ItemTouchHelperExtension mItemTouchHelper;
    public ItemTouchHelperExtension.Callback mCallback;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        List list = getList();
        adapter = new RecyclerAdapter(this, list);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.addItemDecoration(new DividerItemDecoration(this,LinearLayoutManager.VERTICAL));

        mCallback = new ItemTouchHelperCallback();
        mItemTouchHelper = new ItemTouchHelperExtension(mCallback);
        mItemTouchHelper.attachToRecyclerView(recyclerView);
        recyclerView.setAdapter(adapter);

    }

    private List getList() {
        List list = new ArrayList<>();
        for (int i = 0; i < imageUrl.length; i++) {
            ItemModel model = new ItemModel();
            model.setName(names[i]);
            model.setImagePath(imageUrl[i]);
            list.add(model);
        }
        return list;
    }
}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?&gt
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.sunil.swipedeleteitemrecyclervieew.MainActivity">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
        </android.support.v7.widget.RecyclerView>

</RelativeLayout>

list_item.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:orientation="vertical"
    android:id="@+id/view_list_main_content"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="10dp"
    android:background="@android:color/white"
    tools:showIn="@layout/list_item_main">

    <de.hdodenhof.circleimageview.CircleImageView
        android:src="@mipmap/ic_launcher"
        android:id="@+id/imageView"
        android:layout_width="70dp"
        android:layout_height="70dp" />

    <TextView
        android:id="@+id/name"
        android:text="name"
        android:textStyle="bold"
        android:layout_alignBaseline="@id/imageView"
        android:layout_margin="10dp"
        android:gravity="center_vertical"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_toRightOf="@+id/imageView"/>

</RelativeLayout>

list_item_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#FF4444">

   <LinearLayout
        android:id="@+id/view_list_repo_action_container"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="right"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/view_list_repo_action_delete"
            android:layout_width="80dp"
            android:layout_height="match_parent"
            android:gravity="center"
            android:padding="12dp"
            android:text="Delete"
            android:textColor="@android:color/white"/>

        <TextView
            android:id="@+id/view_list_repo_action_update"
            android:layout_width="80dp"
            android:layout_height="match_parent"
            android:background="#8BC34A"
            android:gravity="center"
            android:padding="12dp"
            android:text="Refresh"
            android:textColor="@android:color/white"/>

    </LinearLayout&gt
   <include layout="@layout/item_layout"/>
</FrameLayout>

list_item_single_delete.xml

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

    <LinearLayout
        android:id="@+id/view_list_repo_action_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="right"
        android:background="#FF4444"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/view_list_repo_action_delete"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_vertical"
            android:padding="12dp"
            android:text="Delete ?"
            android:textColor="@android:color/white"/>

       <TextView
            android:id="@+id/view_list_repo_action_undo"
            android:layout_width="80dp"
            android:layout_height="match_parent"
            android:gravity="center"
            android:padding="12dp"
            android:text="Undo"
            android:textColor="@android:color/white"/>

    </LinearLayout&gt

   <include layout="@layout/item_layout"/>

</FrameLayout>

RecyclerAdapter.java

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;

import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * Created by sunil on 11/29/16.
 */

public class RecyclerAdapter extends RecyclerView.Adapter {

    private List itemModels;
    private Context context;
    public static final int ITEM_TYPE_RECYCLER_WIDTH = 1000;
    public static final int ITEM_TYPE_ACTION_WIDTH = 1001;
    public static final int ITEM_TYPE_ACTION_WIDTH_NO_SPRING = 1002;

    public RecyclerAdapter(Context context, List wallTalls) {
        this.itemModels = wallTalls;
        this.context = context;
    }

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


    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item_main, viewGroup, false);
        if (viewType == ITEM_TYPE_ACTION_WIDTH)
            return new ItemSwipeWithActionWidthViewHolder(view);
        if (viewType == ITEM_TYPE_RECYCLER_WIDTH) {
            view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item_with_single_delete, viewGroup, false);
            return new ItemViewHolderWithRecyclerWidth(view);
        }
        return new ItemSwipeWithActionWidthNoSpringViewHolder(view);


    }

    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
        ItemModel model = itemModels.get(position);
        initializeViews(model, holder, position);

        if (holder instanceof ItemViewHolderWithRecyclerWidth) {
            ItemViewHolderWithRecyclerWidth viewHolder = (ItemViewHolderWithRecyclerWidth) holder;
            viewHolder.mActionViewDelete.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    doDelete(holder.getAdapterPosition());
                }
            });
        } else if (holder instanceof ItemSwipeWithActionWidthViewHolder) {
            ItemSwipeWithActionWidthViewHolder viewHolder = (ItemSwipeWithActionWidthViewHolder) holder;
            viewHolder.mActionViewRefresh.setOnClickListener(
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            Toast.makeText(context, "Refresh Click" + holder.getAdapterPosition()
                                    , Toast.LENGTH_SHORT).show();
                        }
                    }

            );
            viewHolder.mActionViewDelete.setOnClickListener(
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            doDelete(holder.getAdapterPosition());
                        }
                    }

            );
        }

    }

    private void doDelete(int adapterPosition) {
        itemModels.remove(adapterPosition);
        notifyItemRemoved(adapterPosition);
    }


    @Override
    public int getItemViewType(int position) {
        if (position == 1) {
            return ITEM_TYPE_ACTION_WIDTH_NO_SPRING;
        }
        if (position == 2) {
            return ITEM_TYPE_RECYCLER_WIDTH;
        }
        return ITEM_TYPE_ACTION_WIDTH;
    }



    private void initializeViews(ItemModel model, final RecyclerView.ViewHolder holder, int position) {

        String imageUrl = model.getImagePath();
        if (imageUrl != null && !imageUrl.isEmpty()){
            Glide.with(context)
                    .load(imageUrl)
                    .into(((ItemViewHolder)holder).imageView);

        }
        ((ItemViewHolder)holder).name.setText(model.getName());
    }

    class ItemViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.name)
        TextView name;
        @BindView(R.id.imageView)
        ImageView imageView;

        @BindView(R.id.view_list_repo_action_container)
        View mActionContainer;

        @BindView(R.id.view_list_main_content)
        View mViewContent;

        public ItemViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }



    class ItemViewHolderWithRecyclerWidth extends ItemViewHolder {

        @BindView(R.id.view_list_repo_action_delete)
        View mActionViewDelete;

        public ItemViewHolderWithRecyclerWidth(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }

    }

    class ItemSwipeWithActionWidthViewHolder extends ItemViewHolder implements Extension {

        @BindView(R.id.view_list_repo_action_delete)
        View mActionViewDelete;
        @BindView(R.id.view_list_repo_action_update)
        View mActionViewRefresh;

        public ItemSwipeWithActionWidthViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }

        @Override
        public float getActionWidth() {
            return mActionContainer.getWidth();
        }
    }

    class ItemSwipeWithActionWidthNoSpringViewHolder extends ItemSwipeWithActionWidthViewHolder implements Extension {

        public ItemSwipeWithActionWidthNoSpringViewHolder(View itemView) {
            super(itemView);
        }

        @Override
        public float getActionWidth() {
            return mActionContainer.getWidth();
        }
    }
}


Thanks for reading this article. I hope it helps you to understand.

Monday, 28 November 2016

Expandable Item In RecyclerView in Android

In my last articles we have learned about the basic of recyclerView. If you have not seen my last article please check those article that really helps you. Here are the link details.
Multiple view type recyclerView and Section recyclerView.

Now in this article I am focusing about core feature of recyclerView and major used in the current building apps that is Expandable Item in recyclerView. You can expand and collapse the item of recyclerView to see the subitems of particular item. In the old API android provides the ListViewExpandable class the provides the feature to expand and collapse item of group. But in RecyclerView there is no specific Control to handle this.

While implementing this feature I found best library that make my work very simple. But if you want any specific expand feature you can feel free to choose any one as per your requirement.
Here is uploaded video by me that helps you to understand, please check this video.


Lets create the android project to implements the expandable and collapsable item in RecyclerView.
Here are the details of Code that required to achieve this feature.


build.gradle app level

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.0"
    defaultConfig {
        applicationId "com.sunil.expandablerecyclerview"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.0.0'
    testCompile 'junit:junit:4.12'

    compile 'com.thoughtbot:expandablerecyclerview:1.0'
    compile 'com.android.support:recyclerview-v7:25.0.0'
    compile 'com.android.support:cardview-v7:25.0.0'
    compile 'com.android.support:design:25.0.0'

    compile 'com.jakewharton:butterknife:8.4.0'
    apt 'com.jakewharton:butterknife-compiler:8.4.0'

    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'de.hdodenhof:circleimageview:2.0.0'
}


MainActivity.java

public class MainActivity extends AppCompatActivity {

    String imageUrl[] = Constant.image;
    String names[] = Constant.name;
    String subNames[] = Constant.subName;

    @BindView(R.id.recyclerView)
    RecyclerView recyclerView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        List list = getList();
        RecyclerAdapter adapter = new RecyclerAdapter(this, list);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(adapter);
        recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
        recyclerView.setAdapter(adapter);

    }

    private List getList() {
        List list = new ArrayList<>();
        for (int i = 0; i < imageUrl.length; i++) {
            List subTitles = new ArrayList<>();
            for (int j = 0; j< subNames.length; j++){
                SubTitle subTitle = new SubTitle(subNames[j]);
                subTitles.add(subTitle);
            }
            Title model = new Title(names[i],subTitles, imageUrl[i]);
            list.add(model);
        }
        return list;
    }
}

RecyclerAdapter.java

public class RecyclerAdapter extends ExpandableRecyclerViewAdapter {

    private Context context;
    public RecyclerAdapter(Context context, List groups) {
        super(groups);
        this.context = context;
    }

    @Override
    public TitleViewHolder onCreateGroupViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.list_item_title, parent, false);
        return new TitleViewHolder(view);
    }

    @Override
    public SubTitleViewHolder onCreateChildViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.list_item_subtitle, parent, false);
        return new SubTitleViewHolder(view);
    }

    @Override
    public void onBindChildViewHolder(SubTitleViewHolder holder, int flatPosition,
                                      ExpandableGroup group, int childIndex) {

        final SubTitle subTitle = ((Title) group).getItems().get(childIndex);
        holder.setSubTitletName(subTitle.getName());
    }

    @Override
    public void onBindGroupViewHolder(TitleViewHolder holder, int flatPosition, ExpandableGroup group) {
        holder.setGenreTitle(context, group);
    }
}

TitleViewHolder.java

public class TitleViewHolder extends GroupViewHolder {

    private TextView titleName;
    private ImageView arrow;
    private ImageView icon;

    public TitleViewHolder(View itemView) {
        super(itemView);
        titleName = (TextView) itemView.findViewById(R.id.list_item_genre_name);
        arrow = (ImageView) itemView.findViewById(R.id.list_item_genre_arrow);
        icon = (ImageView) itemView.findViewById(R.id.list_item_genre_icon);
    }

    public void setGenreTitle(Context context, ExpandableGroup title) {
        if (title instanceof Title) {
            titleName.setText(title.getTitle());
            if (((Title) title).getImageUrl()!= null && !((Title) title).getImageUrl().isEmpty()){
                Glide.with(context)
                        .load(((Title) title).getImageUrl())
                        .into(icon);

            }
        }
    }

    @Override
    public void expand() {
        animateExpand();
    }

    @Override
    public void collapse() {
        animateCollapse();
    }

    private void animateExpand() {
        RotateAnimation rotate =
                new RotateAnimation(360, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        rotate.setDuration(300);
        rotate.setFillAfter(true);
        arrow.setAnimation(rotate);
    }

    private void animateCollapse() {
        RotateAnimation rotate =
                new RotateAnimation(180, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        rotate.setDuration(300);
        rotate.setFillAfter(true);
        arrow.setAnimation(rotate);
    }
}

SubTitleViewHolder.java

public class SubTitleViewHolder extends ChildViewHolder {

    private TextView subTitleTextView;

    public SubTitleViewHolder(View itemView) {
        super(itemView);
        subTitleTextView = (TextView) itemView.findViewById(R.id.subtitle);
    }

    public void setSubTitletName(String name) {
        subTitleTextView.setText(name);
    }
}


Thanks for reading this post. I hope it will helps you to understand.

Saturday, 26 November 2016

Multiple View Type in RecyclerView in Android

Today I am focusing about the multiple view type in recyclerView.  RecyclerView provides many awesome feature to build awesome app.  In one of them is multiple view type RecyclerView.

Now the people wants app with complex layout and design with multiple view style. Users mind has changed they do not like single view recyclerView. They are like one place cover almost things in single design. So in this case multiple view type is play very important role to build this type of design and layout.

RecyclerView adapter provides the multiple view type according to your requirement. It will inflate only those view which is required that position.  In this article I am showing the four different type of view.  Here are the details.

1. Header View Type.
2. One Column View Type.
3. Two Column View Type.
4. Footer ViewType.

Header and footer is very common to add different View on top of Item of RecyclerView and Footer View you can add the bottom of the item of the recyclerView. In between you can change view type multiple types. Here in this example I used two different View Type One column and two column View type. Here is snap shot that helps to understand.





Ok sounds good. Lets check how you can make your adapter multiple view type.

build.gradle app level

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.0"
    defaultConfig {
        applicationId "com.sunil.multityperecyclerview"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.0.0'
    testCompile 'junit:junit:4.12'

    compile 'com.android.support:recyclerview-v7:25.0.0'
    compile 'com.android.support:cardview-v7:25.0.0'
    compile 'com.android.support:design:25.0.0'

    compile 'com.jakewharton:butterknife:8.4.0'
    apt 'com.jakewharton:butterknife-compiler:8.4.0'

    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'de.hdodenhof:circleimageview:2.0.0'
    compile 'com.android.support:percent:25.0.0'
}

MainActivity.java

public class MainActivity extends AppCompatActivity {

    String imageUrl[] = Constant.image;
    String names[] = Constant.name;

    @BindView(R.id.recyclerView)
    RecyclerView recyclerView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        List list = getList();
        MultiTypeRecyclerAdapter adapter = new MultiTypeRecyclerAdapter(this, list);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(adapter);
        recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
        recyclerView.setAdapter(adapter);

    }

    private List getList() {
        List list = new ArrayList<>();
        for (int i = 0; i < imageUrl.length; i++) {
            ItemModel model = new ItemModel();
            model.setName(names[i]);
            model.setImagePath(imageUrl[i]);
            list.add(model);
        }
        return list;
    }
}

MultiTypeRecyclerAdapter.java

public class MultiTypeRecyclerAdapter extends RecyclerView.Adapter {

    private List itemModels;
    private Context context;
    private int HEADER_TYPE =0;
    private int FOOTER_TYPE = 1;
    private int ONE_COLUMN_ROW_TYPE = 2;
    private int TWO_COLUMN_ROW_TYPE =3;

    public MultiTypeRecyclerAdapter(Context context, List wallTalls) {
        this.itemModels = wallTalls;
        this.context = context;
    }

    @Override
    public int getItemCount() {
        return itemModels.size()+2;
    }

    @Override
    public int getItemViewType(int position) {

        if (position == 0){
            return HEADER_TYPE;
        }else if (position == itemModels.size()+1){
            return FOOTER_TYPE;
        }else if (position % 2 == 0){
            return ONE_COLUMN_ROW_TYPE;
        }else{
            return TWO_COLUMN_ROW_TYPE;
        }
    }


    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        View itemView = null;
        if (viewType == HEADER_TYPE){
            itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.header_view, viewGroup, false);
            return new HeaderViewHolder(itemView);
        }else if (viewType == FOOTER_TYPE){
            itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.footer_view, viewGroup, false);
            return new FooterViewHolder(itemView);
        }else if (viewType == ONE_COLUMN_ROW_TYPE){
            itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_layout_one_column, viewGroup, false);
            return new OneColumnViewHolder(itemView);
        }else if (viewType == TWO_COLUMN_ROW_TYPE){
            itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_layout_two_column, viewGroup, false);
            return new TwoColumnViewHolder(itemView);
        }else{
            // default one column row
            itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_layout_one_column, viewGroup, false);
            return new OneColumnViewHolder(itemView);
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        if (holder instanceof HeaderViewHolder){

        }else if (holder instanceof FooterViewHolder){


        }else if (holder instanceof OneColumnViewHolder){

            ItemModel model = itemModels.get(position-1);
            String imageUrl = model.getImagePath();
            if (imageUrl != null && !imageUrl.isEmpty()){
                Glide.with(context)
                        .load(imageUrl)
                        // .placeholder(R.drawable.i)
                        .into(((OneColumnViewHolder)holder).imageView);

            }
            ((OneColumnViewHolder)holder).name.setText(model.getName());

        }else if (holder instanceof TwoColumnViewHolder){

            ItemModel model = itemModels.get(position-1);
            String imageUrl = model.getImagePath();
            if (imageUrl != null && !imageUrl.isEmpty()){
                Glide.with(context)
                        .load(imageUrl)
                        .into(((TwoColumnViewHolder)holder).imageView);

                Glide.with(context)
                        .load(imageUrl)
                        .into(((TwoColumnViewHolder)holder).imageView1);


            }
            ((TwoColumnViewHolder)holder).name.setText(model.getName());
            ((TwoColumnViewHolder)holder).name1.setText(model.getName());

        }else{

            ItemModel model = itemModels.get(position-1);
            String imageUrl = model.getImagePath();
            if (imageUrl != null && !imageUrl.isEmpty()){
                Glide.with(context)
                        .load(imageUrl)
                        // .placeholder(R.drawable.i)
                        .into(((OneColumnViewHolder)holder).imageView);

            }
            ((OneColumnViewHolder)holder).name.setText(model.getName());
        }

    }


    public static class OneColumnViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.name)
        TextView name;
        @BindView(R.id.imageView)
        ImageView imageView;

        public OneColumnViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }

    public static class TwoColumnViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.name)
        TextView name;
        @BindView(R.id.imageView)
        ImageView imageView;

        @BindView(R.id.name1)
        TextView name1;
        @BindView(R.id.imageView1)
        ImageView imageView1;

        public TwoColumnViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }

    public static class HeaderViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.headerView)
        TextView header;

        public HeaderViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }


    public static class FooterViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.footerView)
        TextView footer;

        public FooterViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }
}


Thanks for reading this post. I hope it will help you to understand.

Section RecyclerView in Android

In the last article We have learned about the some of features of recyclerView . If you did not seen then Please have  a look on this links ViewPager Item in RecyclerView and Drag n Drop item in RecyclerView.

In this article I am describing the Section in recyclerView. Section is dividing the list items in to sections. For example I am showing three sections "Weekends' , "Favorites" and "Offers".
Here is uploaded video that presents the Sections in ListView and GridView formate in RecyclerView.


To implements this section I got help from this link SectionRecyclerViewAdapter.
Lets create an android studio project to implements section recyclerView.

build.gradle app level

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.0"
    defaultConfig {
        applicationId "com.sunil.sectionrecyclerview"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.0.0'
    testCompile 'junit:junit:4.12'

    compile 'com.android.support:recyclerview-v7:25.0.0'
    compile 'com.android.support:cardview-v7:25.0.0'
    compile 'com.android.support:design:25.0.0'

    compile 'com.jakewharton:butterknife:8.4.0'
    apt 'com.jakewharton:butterknife-compiler:8.4.0'

    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'de.hdodenhof:circleimageview:2.0.0'
}


ListActivity.java

public class ListActivity extends AppCompatActivity{

    String imageUrl[] = Constant.image;
    String names[] = Constant.name;

    @BindView(R.id.recyclerView)
    RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.acivity_listview);
        ButterKnife.bind(this);

        List list = getList();
        RecyclerAdapter adapter = new RecyclerAdapter(this, list);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(adapter);
        recyclerView.addItemDecoration(new DividerItemDecoration(this,LinearLayoutManager.VERTICAL));

        //This is the code to provide a sectioned list
        List sections =
                new ArrayList();

        //Sections
        sections.add(new SectionedRecyclerViewAdapter.Section(0,"Weekends"));
        sections.add(new SectionedRecyclerViewAdapter.Section(2,"Favorites"));
        sections.add(new SectionedRecyclerViewAdapter.Section(4,"Offers"));

        //Add your adapter to the sectionAdapter
        SectionedRecyclerViewAdapter.Section[] dummy = new SectionedRecyclerViewAdapter.Section[sections.size()];
        SectionedRecyclerViewAdapter mSectionedAdapter = new
                SectionedRecyclerViewAdapter(this,R.layout.item_section, R.id.sectionName, adapter);
        mSectionedAdapter.setSections(sections.toArray(dummy));

        //Apply this adapter to the RecyclerView
        recyclerView.setAdapter(mSectionedAdapter);

    }

    private List getList() {
        List list = new ArrayList<>();
        for (int i = 0; i < imageUrl.length; i++) {
            ItemModel model = new ItemModel();
            model.setName(names[i]);
            model.setImagePath(imageUrl[i]);
            list.add(model);
        }
        return list;
    }
}

GridViewActivity.java

public class GridViewActivity extends Activity{


    String imageUrl[] = Constant.image;
    String names[] = Constant.name;

    @BindView(R.id.recyclerView)
    RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.acivity_listview);
        ButterKnife.bind(this);

        List list = getList();
        RecyclerAdapter adapter = new RecyclerAdapter(this, list);
        recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
        recyclerView.setAdapter(adapter);
        recyclerView.addItemDecoration(new DividerItemDecoration(this,LinearLayoutManager.VERTICAL));

        //This is the code to provide a sectioned list
        List sections =
                new ArrayList();

        //Sections
        sections.add(new SectionedGridRecyclerViewAdapter.Section(0,"Weekends"));
        sections.add(new SectionedGridRecyclerViewAdapter.Section(3,"Favorites"));

        //Add your adapter to the sectionAdapter
        SectionedGridRecyclerViewAdapter.Section[] dummy = new SectionedGridRecyclerViewAdapter.Section[sections.size()];
        SectionedGridRecyclerViewAdapter mSectionedAdapter = new
                SectionedGridRecyclerViewAdapter(this ,R.layout.item_section, R.id.sectionName, recyclerView, adapter);
        mSectionedAdapter.setSections(sections.toArray(dummy));

        //Apply this adapter to the RecyclerView
        recyclerView.setAdapter(mSectionedAdapter);

    }

    private List getList() {
        List list = new ArrayList<>();
        for (int i = 0; i < imageUrl.length; i++) {
            ItemModel model = new ItemModel();
            model.setName(names[i]);
            model.setImagePath(imageUrl[i]);
            list.add(model);
        }
        return list;
    }
}

RecyclerAdapter.java

public class RecyclerAdapter extends RecyclerView.Adapter {

    private List itemModels;
    private Context context;

    public RecyclerAdapter(Context context, List wallTalls) {
        this.itemModels = wallTalls;
        this.context = context;
    }

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


    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_layout, viewGroup, false);
        return new ItemViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        ItemModel model = itemModels.get(position);
        initializeViews(model, holder, position);
    }


    private void initializeViews(ItemModel model, final RecyclerView.ViewHolder holder, int position) {

        String imageUrl = model.getImagePath();
        if (imageUrl != null && !imageUrl.isEmpty()){
            Glide.with(context)
                    .load(imageUrl)
                   // .placeholder(R.drawable.i)
                    .into(((ItemViewHolder)holder).imageView);

        }
        ((ItemViewHolder)holder).name.setText(model.getName());
    }

    public static class ItemViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.name)
        TextView name;
        @BindView(R.id.imageView)
        ImageView imageView;

        public ItemViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }
}





Thanks for reading this post. I hope it will understand to you.

Friday, 25 November 2016

ViewPager Item of Recycler view in android

In my last article We learned how to Drag and Drop Item In RecyclerView. If you did not check Please see the above link that explained about the RecyclerView basic info.

Today We have learned about How to use View Pager inside the recyclerView to maintain the scrolling of view pager and recyclerView.  In this article I want to present set of image to scroll with help of ViewPager and scroll item of RecyclerView. This concepts used many apps to show their products. Please check my video that helps to understand the feature.



Lets start to create the android studio project to implements the same feature which is introduced in this video. In this project I used the GreenDao wrapper for local database. I will stored the some of image url into db and fetched at the time of show on recyclerview.
If you not aware about the Green Dao wrapper of sqlite Please check my last article that helps you to understand . Here is the link Green Dao fast ORM in android.

build.gradle app level

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'org.greenrobot.greendao'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.0"
    defaultConfig {
        applicationId "com.sunil.recyclerviewviewpager"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

greendao {
    targetGenDir 'src/main/java'
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.0.0'
    testCompile 'junit:junit:4.12'

    compile 'com.android.support:recyclerview-v7:25.0.0'
    compile 'com.android.support:cardview-v7:25.0.0'
    compile 'com.android.support:design:25.0.0'

    compile 'com.jakewharton:butterknife:8.4.0'
    apt 'com.jakewharton:butterknife-compiler:8.4.0'

    compile 'com.github.bumptech.glide:glide:3.7.0'

    compile 'org.greenrobot:greendao:3.2.0'
    compile 'net.zetetic:android-database-sqlcipher:3.5.1'

}


MainActivity.java

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.recyclerView)
    RecyclerView recyclerView;
    @BindView(R.id.activity_main)
    RelativeLayout activityMain;

    String [] name = {"Bangalore", "Chennai", "Kolkata", "Delhi", "Mumbai", "Pune"};
    String [] image = {"http://farm8.staticflickr.com/7452/27782542462_12e206359b_m.jpg",
                       "http://farm8.staticflickr.com/7311/27782539412_1e1cece561_m.jpg",
                        "http://farm8.staticflickr.com/7452/27782542462_12e206359b_m.jpg",
                         "http://farm8.staticflickr.com/7326/27605634010_917553d601_m.jpg",
                         "http://farm8.staticflickr.com/7452/27782542462_12e206359b_m.jpg",
                        "http://farm8.staticflickr.com/7311/27782539412_1e1cece561_m.jpg"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        insertIntoDb();
        getInfo();
    }

    private void getInfo() {
        List listWall= WallTallManager.loadAll(this);
        LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(mLayoutManager);
        WallAdapter adapter = new WallAdapter(this, listWall);
        recyclerView.setAdapter(adapter);
        DividerItemDecoration mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), mLayoutManager.getOrientation());
        recyclerView.addItemDecoration(mDividerItemDecoration);
    }

    private void insertIntoDb(){
        WallTallManager.removeAll(this);
        DataManager.removeAll(this);
        for (int index =0; index < 2; index++){
            WallTall wallTall = new WallTall();
            wallTall.setName_id(index);
            WallTallManager.insertOrReplace(this,wallTall);

            for (int i =0; i<6; i++) {
                DataWall dataWall = new DataWall();
                dataWall.setName_id(index);
                dataWall.setName(name[i]);
                dataWall.setImageurl(image[i]);
                DataManager.insertOrReplace(this,dataWall);
            }

        }
    }
}

activity_main.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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.sunil.recyclerviewviewpager.MainActivity"/>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</RelativeLayout/>

WallAdapter.java

public class WallAdapter extends RecyclerView.Adapter {

    private List wallTalls;
    private Context context;

    public WallAdapter(Context context, List wallTalls) {
        this.wallTalls = wallTalls;
        this.context = context;
    }

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


    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_layout, viewGroup, false);
        return new WallViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        int name_id = wallTalls.get(position).getName_id();
        List dataModelList = DataManager.loadByQuery(context, name_id);
        initializeViews(dataModelList, holder, position);
    }


    private void initializeViews(List dataModel, final RecyclerView.ViewHolder holder, int position) {
        ViewPagerAdapter adapter = new ViewPagerAdapter(dataModel);
        ((WallViewHolder)holder).viewPager.setAdapter(adapter);
        ((WallViewHolder)holder).viewPager.setClipToPadding(false);
        ((WallViewHolder)holder).viewPager.setPadding(40, 0, 40, 0);
        if (position == 0) {
            ((WallViewHolder) holder).title.setText("Weekend Shop");
        }
        else{
            ((WallViewHolder)holder).title.setText("Favorite Shop");
        }
    }

    public static class WallViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.view_pager)
        ViewPager viewPager;

        @BindView(R.id.title)
        TextView title;

        public WallViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }
}

ViewPagerAdapter.java

public class ViewPagerAdapter extends PagerAdapter{

    List dataModels;
   public ViewPagerAdapter(List dataModels){
        this.dataModels = dataModels;
    }

    @Override
    public int getCount() {
        return dataModels.size();
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View itemView = LayoutInflater.from(container.getContext()).inflate(R.layout.view_pager_row, container, false);
        ImageView imageViewCampaign = (ImageView) itemView.findViewById(R.id.imageview_campaign);
        TextView textViewCampaign = (TextView) itemView.findViewById(R.id.textview_campaign);
        DataWall wall = dataModels.get(position);
        String imageUrl = wall.getImageurl();
        if (imageUrl != null && !imageUrl.isEmpty()){
            Glide.with(container.getContext())
                    .load(imageUrl)
                    .centerCrop()
                    //.placeholder(R.drawable.ic)
                    .crossFade()
                    .into(imageViewCampaign);

        }
        textViewCampaign.setText(wall.getName());
        container.addView(itemView);
        return itemView;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        ((ViewPager) container).removeView((View) object);
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }
}

Thanks for reading this post. I hope it will helps to understand.

Thursday, 24 November 2016

Drag and Drop Item in RecyclerView in Android

RecyclerView is the main feature of any app. It mostly used in building android app. RecyclerView comes in material design. It gives better user experience to bind the data and show in list. It gives better experience than ListView. Today people are using more complex design layout that difficult to handle by ListView.

ListView will be obsolete in next coming days. It failed to provide better animation and multiple view click on Item. That why introduced RecyclerView.
Its provide better scrolling and animation while adding item and removing item. Now today we are learning about how to drag and drop item in recyclerView. RecyclerView provide better experience in drag and drop item. You can set the order of items. Here is the video that what I am talking about Please check it.



Lets create android project by Android studio. you need to add dependency for recycler-view.
I used some of dependencies that makes better user interface. 

build.gradle app level

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.sunil.recyclerviewdragndropitem"
        minSdkVersion 14
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:design:23.1.1'
    compile 'de.hdodenhof:circleimageview:2.0.0'
    compile 'com.jakewharton:butterknife:7.0.1'
    compile 'com.android.support:recyclerview-v7:23.1.0'
    compile 'com.squareup.picasso:picasso:2.5.2'
    compile 'com.android.support:cardview-v7:23.1.0'
}


ItemModel.java

/**
 * Created by sunil on 27-Feb-16.
 */
public class ItemModel {
    
    private String name;
    private String imagePath;

    public ItemModel(String name, String imagePath) {
        this.name = name;
        this.imagePath = imagePath;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getImagePath() {
        return imagePath;
    }

    public void setImagePath(String imagePath) {
        this.imagePath = imagePath;
    }
}



RecyclerView ItemTouchHelper.Callback is class that provide the listener to identify the item movement flag while either by long pressed or touch of item or swipe the item. With this help we can drag our item positions.

EditItemTouchHelperCallback.java

public class EditItemTouchHelperCallback extends ItemTouchHelper.Callback {

    private final ItemAdapter mAdapter;

    public EditItemTouchHelperCallback(ItemAdapter adapter) {
        mAdapter = adapter;
    }

    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }

    @Override
    public boolean isItemViewSwipeEnabled() {
        return false;
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
                          RecyclerView.ViewHolder target) {
        mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
    }

}


MainActivity.java

package com.sunil.recyclerviewdragndropitem;

public class MainActivity extends AppCompatActivity implements OnStartDragListener{

    @Bind(R.id.recycler_view)
    RecyclerView mRecyclerView;
    ItemTouchHelper mItemTouchHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        ButterKnife.bind(this);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });


        List list = Utility.getListPerson();

        mRecyclerView.setHasFixedSize(true);
        LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        ItemAdapter mAdapter = new ItemAdapter(this, list, this);
        ItemTouchHelper.Callback callback =
                new EditItemTouchHelperCallback(mAdapter);
        mItemTouchHelper = new ItemTouchHelper(callback);
        mItemTouchHelper.attachToRecyclerView(mRecyclerView);

        mRecyclerView.setAdapter(mAdapter);


    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
        mItemTouchHelper.startDrag(viewHolder);
    }
}


ItemAdapter.java

public class ItemAdapter extends RecyclerView.Adapter implements ItemTouchHelperAdapter {

    private List mPersonList;
    OnItemClickListener mItemClickListener;
    private static final int TYPE_ITEM = 0;
    private final LayoutInflater mInflater;
    private final OnStartDragListener mDragStartListener;
    private Context mContext;

    public ItemAdapter(Context context, List list, OnStartDragListener dragListner) {
        this.mPersonList = list;
        this.mInflater = LayoutInflater.from(context);
        mDragStartListener = dragListner;
        mContext = context;

    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

        if (viewType == TYPE_ITEM) {
            //inflate your layout and pass it to view holder
            View v = mInflater.inflate(R.layout.person_item, viewGroup, false);
            return new VHItem(v );
        }

        throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");

    }

    @Override
    public int getItemViewType(int position) {
            return TYPE_ITEM;
    }



    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int i) {

        if (viewHolder instanceof VHItem) {

            final VHItem holder= (VHItem)viewHolder;
            ((VHItem) viewHolder).title.setText(mPersonList.get(i).getName());
            Picasso.with(mContext)
                    .load(mPersonList.get(i).getImagePath())
                    .placeholder(R.drawable.ic_profile)
                    .into(((VHItem) viewHolder).imageView);

            ((VHItem) viewHolder).image_menu.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
                        mDragStartListener.onStartDrag(holder);
                    }
                    return false;
                }
            });
        }
    }

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

    public interface OnItemClickListener {
        public void onItemClick(View view, int position);
    }

    public void setOnItemClickListener(final OnItemClickListener mItemClickListener) {
        this.mItemClickListener = mItemClickListener;
    }

    public class VHItem extends RecyclerView.ViewHolder implements View.OnClickListener ,ItemTouchHelperViewHolder{
        public TextView title;
        private ImageView imageView;
        private ImageView image_menu;

        public VHItem(View itemView) {
            super(itemView);
            title = (TextView) itemView.findViewById(R.id.name);
            image_menu = (ImageView) itemView.findViewById(R.id.image_menu);
            imageView = (ImageView) itemView.findViewById(R.id.circle_imageView);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            if (mItemClickListener != null) {
                mItemClickListener.onItemClick(v, getPosition());
            }
        }

        @Override
        public void onItemSelected() {
            itemView.setBackgroundColor(Color.LTGRAY);
        }

        @Override
        public void onItemClear() {
            itemView.setBackgroundColor(0);
        }
    }

    @Override
    public void onItemDismiss(int position) {
        mPersonList.remove(position);
        notifyItemRemoved(position);
    }

    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        //Log.v("", "Log position" + fromPosition + " " + toPosition);
        if (fromPosition < mPersonList.size() && toPosition < mPersonList.size()) {
            if (fromPosition < toPosition) {
                for (int i = fromPosition; i < toPosition; i++) {
                    Collections.swap(mPersonList, i, i + 1);
                }
            } else {
                for (int i = fromPosition; i > toPosition; i--) {
                    Collections.swap(mPersonList, i, i - 1);
                }
            }
            notifyItemMoved(fromPosition, toPosition);
        }
        return true;
    }

    public void updateList(List list) {
        mPersonList = list;
        notifyDataSetChanged();
    }
}


Thanks for reading this post. I hope it will help you.