Slide Image in RecyclerView

Mục đích của bài viết là hướng dẫn cách tạo 1 slide image trong item của recycler view

1. Model, data, view, interface

1.1. Tạo model Profile

Tạo 1 model chứa thông tin Profile : gồm id, name, age, và list image

package tuananh.com.slideimageinrecyclerview.model;

import java.io.Serializable;
import java.util.List;

/**
 * Created by framgia on 27/04/2017.
 */
public class Profile implements Serializable {
    private int mId;
    private String mName;
    private int mAge;
    private List<String> mImageList;

    public Profile(int id, String name, int age, List<String> imageList) {
        mId = id;
        mName = name;
        mAge = age;
        mImageList = imageList;
    }

    public int getId() {
        return mId;
    }

    public void setId(int id) {
        mId = id;
    }

    public String getName() {
        return mName;
    }

    public void setName(String name) {
        mName = name;
    }

    public List<String> getImageList() {
        return mImageList;
    }

    public void setImageList(List<String> imageList) {
        mImageList = imageList;
    }

    public int getAge() {
        return mAge;
    }

    public void setAge(int age) {
        mAge = age;
    }

    public String getNameAge() {
        return String.format("%s, %d", getName(), getAge());
    }
}

1.2. View custom

1.2.1. CircleIndicator

Vẽ và bắt sự kiện scroll viewpage và vẽ lại vị trí của ảnh tương ứng trong list image

package tuananh.com.slideimageinrecyclerview.view.custom;

import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.os.Build;
import android.support.annotation.AnimatorRes;
import android.support.annotation.DrawableRes;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.LinearLayout;

import tuananh.com.slideimageinrecyclerview.R;

import static android.support.v4.view.ViewPager.OnPageChangeListener;

public class CircleIndicator extends LinearLayout {
    private final static int DEFAULT_INDICATOR_WIDTH = 5;
    private ViewPager mViewpager;
    private int mIndicatorMargin = -1;
    private int mIndicatorWidth = -1;
    private int mIndicatorHeight = -1;
    private int mAnimatorResId = R.animator.scale_with_alpha;
    private int mAnimatorReverseResId = 0;
    private int mIndicatorBackgroundResId = R.drawable.blur_radius;
    private int mIndicatorUnselectedBackgroundResId = R.drawable.blur_radius;
    private Animator mAnimatorOut;
    private Animator mAnimatorIn;
    private Animator mImmediateAnimatorOut;
    private Animator mImmediateAnimatorIn;
    private int mLastPosition = -1;
    private final OnPageChangeListener mInternalPageChangeListener = new OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }

        @Override
        public void onPageSelected(int position) {
            if (mViewpager.getAdapter() == null || mViewpager.getAdapter().getCount() <= 0) {
                return;
            }
            if (mAnimatorIn.isRunning()) {
                mAnimatorIn.end();
                mAnimatorIn.cancel();
            }
            if (mAnimatorOut.isRunning()) {
                mAnimatorOut.end();
                mAnimatorOut.cancel();
            }
            View currentIndicator;
            if (mLastPosition >= 0 && (currentIndicator = getChildAt(mLastPosition)) != null) {
                currentIndicator.setBackgroundResource(mIndicatorUnselectedBackgroundResId);
                mAnimatorIn.setTarget(currentIndicator);
                mAnimatorIn.start();
            }
            View selectedIndicator = getChildAt(position);
            if (selectedIndicator != null) {
                selectedIndicator.setBackgroundResource(mIndicatorBackgroundResId);
                mAnimatorOut.setTarget(selectedIndicator);
                mAnimatorOut.start();
            }
            mLastPosition = position;
        }

        @Override
        public void onPageScrollStateChanged(int state) {
        }
    };
    private DataSetObserver mInternalDataSetObserver = new DataSetObserver() {
        @Override
        public void onChanged() {
            super.onChanged();
            if (mViewpager == null) {
                return;
            }
            int newCount = mViewpager.getAdapter().getCount();
            int currentCount = getChildCount();
            if (newCount == currentCount) {  // No change
                return;
            } else if (mLastPosition < newCount) {
                mLastPosition = mViewpager.getCurrentItem();
            } else {
                mLastPosition = -1;
            }
            createIndicators();
        }
    };

    public CircleIndicator(Context context) {
        super(context);
        init(context, null);
    }

    public CircleIndicator(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public CircleIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public CircleIndicator(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        handleTypedArray(context, attrs);
        checkIndicatorConfig(context);
    }

    private void handleTypedArray(Context context, AttributeSet attrs) {
        if (attrs == null) {
            return;
        }
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleIndicator);
        mIndicatorWidth =
            typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_ci_width, -1);
        mIndicatorHeight =
            typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_ci_height, -1);
        mIndicatorMargin =
            typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_ci_margin, -1);
        mAnimatorResId = typedArray.getResourceId(R.styleable.CircleIndicator_ci_animator,
            R.animator.scale_with_alpha);
        mAnimatorReverseResId =
            typedArray.getResourceId(R.styleable.CircleIndicator_ci_animator_reverse, 0);
        mIndicatorBackgroundResId =
            typedArray.getResourceId(R.styleable.CircleIndicator_ci_drawable,
                R.drawable.blur_radius);
        mIndicatorUnselectedBackgroundResId =
            typedArray.getResourceId(R.styleable.CircleIndicator_ci_drawable_unselected,
                mIndicatorBackgroundResId);
        int orientation = typedArray.getInt(R.styleable.CircleIndicator_ci_orientation, -1);
        setOrientation(orientation == VERTICAL ? VERTICAL : HORIZONTAL);
        int gravity = typedArray.getInt(R.styleable.CircleIndicator_ci_gravity, -1);
        setGravity(gravity >= 0 ? gravity : Gravity.CENTER);
        typedArray.recycle();
    }

    /**
     * Create and configure Indicator in Java code.
     */
    public void configureIndicator(int indicatorWidth, int indicatorHeight, int indicatorMargin) {
        configureIndicator(indicatorWidth, indicatorHeight, indicatorMargin,
            R.animator.scale_with_alpha, 0, R.drawable.blur_radius, R.drawable.blur_radius);
    }

    public void configureIndicator(int indicatorWidth, int indicatorHeight, int indicatorMargin,
                                   @AnimatorRes int animatorId, @AnimatorRes int animatorReverseId,
                                   @DrawableRes int indicatorBackgroundId,
                                   @DrawableRes int indicatorUnselectedBackgroundId) {
        mIndicatorWidth = indicatorWidth;
        mIndicatorHeight = indicatorHeight;
        mIndicatorMargin = indicatorMargin;
        mAnimatorResId = animatorId;
        mAnimatorReverseResId = animatorReverseId;
        mIndicatorBackgroundResId = indicatorBackgroundId;
        mIndicatorUnselectedBackgroundResId = indicatorUnselectedBackgroundId;
        checkIndicatorConfig(getContext());
    }

    private void checkIndicatorConfig(Context context) {
        mIndicatorWidth = (mIndicatorWidth < 0) ? dip2px(DEFAULT_INDICATOR_WIDTH) : mIndicatorWidth;
        mIndicatorHeight =
            (mIndicatorHeight < 0) ? dip2px(DEFAULT_INDICATOR_WIDTH) : mIndicatorHeight;
        mIndicatorMargin =
            (mIndicatorMargin < 0) ? dip2px(DEFAULT_INDICATOR_WIDTH) : mIndicatorMargin;
        mAnimatorResId = (mAnimatorResId == 0) ? R.animator.scale_with_alpha : mAnimatorResId;
        mAnimatorOut = createAnimatorOut(context);
        mImmediateAnimatorOut = createAnimatorOut(context);
        mImmediateAnimatorOut.setDuration(0);
        mAnimatorIn = createAnimatorIn(context);
        mImmediateAnimatorIn = createAnimatorIn(context);
        mImmediateAnimatorIn.setDuration(0);
        mIndicatorBackgroundResId = (mIndicatorBackgroundResId == 0) ? R.drawable.blur_radius
            : mIndicatorBackgroundResId;
        mIndicatorUnselectedBackgroundResId =
            (mIndicatorUnselectedBackgroundResId == 0) ? mIndicatorBackgroundResId
                : mIndicatorUnselectedBackgroundResId;
    }

    private Animator createAnimatorOut(Context context) {
        return AnimatorInflater.loadAnimator(context, mAnimatorResId);
    }

    private Animator createAnimatorIn(Context context) {
        Animator animatorIn;
        if (mAnimatorReverseResId == 0) {
            animatorIn = AnimatorInflater.loadAnimator(context, mAnimatorResId);
            animatorIn.setInterpolator(new ReverseInterpolator());
        } else {
            animatorIn = AnimatorInflater.loadAnimator(context, mAnimatorReverseResId);
        }
        return animatorIn;
    }

    public void setViewPager(ViewPager viewPager) {
        mViewpager = viewPager;
        if (mViewpager != null && mViewpager.getAdapter() != null) {
            mLastPosition = -1;
            createIndicators();
            mViewpager.removeOnPageChangeListener(mInternalPageChangeListener);
            mViewpager.addOnPageChangeListener(mInternalPageChangeListener);
            mInternalPageChangeListener.onPageSelected(mViewpager.getCurrentItem());
        }
    }

    public DataSetObserver getDataSetObserver() {
        return mInternalDataSetObserver;
    }

    /**
     * @deprecated User ViewPager addOnPageChangeListener
     */
    @Deprecated
    public void setOnPageChangeListener(OnPageChangeListener onPageChangeListener) {
        if (mViewpager == null) {
            throw new NullPointerException("can not find Viewpager , setViewPager first");
        }
        mViewpager.removeOnPageChangeListener(onPageChangeListener);
        mViewpager.addOnPageChangeListener(onPageChangeListener);
    }

    private void createIndicators() {
        removeAllViews();
        int count = mViewpager.getAdapter().getCount();
        if (count <= 0) {
            return;
        }
        int currentItem = mViewpager.getCurrentItem();
        int orientation = getOrientation();
        for (int i = 0; i < count; i++) {
            if (currentItem == i) {
                addIndicator(orientation, mIndicatorBackgroundResId, mImmediateAnimatorOut);
            } else {
                addIndicator(orientation, mIndicatorUnselectedBackgroundResId,
                    mImmediateAnimatorIn);
            }
        }
    }

    private void addIndicator(int orientation, @DrawableRes int backgroundDrawableId,
                              Animator animator) {
        if (animator.isRunning()) {
            animator.end();
            animator.cancel();
        }
        View Indicator = new View(getContext());
        Indicator.setBackgroundResource(backgroundDrawableId);
        addView(Indicator, mIndicatorWidth, mIndicatorHeight);
        LayoutParams lp = (LayoutParams) Indicator.getLayoutParams();
        if (orientation == HORIZONTAL) {
            lp.leftMargin = mIndicatorMargin;
            lp.rightMargin = mIndicatorMargin;
        } else {
            lp.topMargin = mIndicatorMargin;
            lp.bottomMargin = mIndicatorMargin;
        }
        Indicator.setLayoutParams(lp);
        animator.setTarget(Indicator);
        animator.start();
    }

    public int dip2px(float dpValue) {
        final float scale = getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    private class ReverseInterpolator implements Interpolator {
        @Override
        public float getInterpolation(float value) {
            return Math.abs(1.0f - value);
        }
    }
}

1.2.2 ResizableImageView

Resize Image theo chiều rộng mà ko vỡ ảnh

package tuananh.com.slideimageinrecyclerview.view.custom;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

/**
 * Created by TuanAnh on 4/28/2017.
 */
public class ResizableImageView extends ImageView {
    public ResizableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Drawable d = getDrawable();
        if (d != null) {
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int height = 0;
            height = (int) Math.ceil((float) width
                * (float) d.getIntrinsicHeight()
                / (float) d.getIntrinsicWidth());
            setMeasuredDimension(width, height);
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
}

1.3. Tạo class create data

Khởi tạo list profile cho ứng dụng

package tuananh.com.slideimageinrecyclerview;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import tuananh.com.slideimageinrecyclerview.model.Profile;

/**
 * Created by framgia on 27/04/2017.
 */
public class CreateData {
    public static List<Profile> createProfile() {
        List<Profile> profileList = new ArrayList<>();
        profileList.add(create(1, "Đào", 22, Arrays.asList(
            "http://imageshack.com/a/img922/986/1C5zeO.jpg",
            "http://imageshack.com/a/img924/224/taTtUg.jpg",
            "http://imageshack.com/a/img923/1333/cnHzDa.jpg",
            "http://imageshack.com/a/img922/9823/TpA14D.jpg",
            "http://imageshack.com/a/img924/4017/f9pqLq.jpg",
            "http://imageshack.com/a/img922/8958/4KAmdD.jpg",
            "http://imageshack.com/a/img923/8135/nyfIov.jpg")));
        profileList.add(create(2, "Đào", 22, Arrays.asList(
            "http://imageshack.com/a/img923/2374/jBIAqT.jpg",
            "http://imageshack.com/a/img923/9599/ulegwM.jpg",
            "http://imageshack.com/a/img923/7016/HzEvo8.jpg",
            "http://imageshack.com/a/img922/1641/emfvPy.jpg",
            "http://imageshack.com/a/img923/116/yfyetV.jpg",
            "http://imageshack.com/a/img924/4846/zveut5.jpg",
            "http://imageshack.com/a/img923/472/SB341D.jpg",
            "http://imageshack.com/a/img924/4350/5ghok1.jpg")));
        profileList.add(create(3, "Đào", 22, Arrays.asList(
            "http://imageshack.com/a/img923/3835/q79WKE.jpg",
            "http://imageshack.com/a/img922/3615/sNKPpV.jpg",
            "http://imageshack.com/a/img924/7272/UXID41.jpg",
            "http://imageshack.com/a/img923/1332/sTx6qw.jpg",
            "http://imageshack.com/a/img923/3338/v0hyg5.jpg",
            "http://imageshack.com/a/img922/8435/puIYQa.jpg")));
        profileList.add(create(4, "Đào", 22, Arrays.asList(
            "http://imageshack.com/a/img922/3390/GXOW9e.jpg",
            "http://imageshack.com/a/img922/8017/Qnxgbw.jpg")));
        profileList.add(create(5, "Đào", 22, Arrays.asList(
            "http://imageshack.com/a/img924/331/ujExV6.jpg",
            "http://imageshack.com/a/img923/9503/qgUaHN.jpg",
            "http://imageshack.com/a/img924/5319/RNBJQp.jpg",
            "http://imageshack.com/a/img923/3299/nWdFeZ.jpg",
            "http://imageshack.com/a/img922/461/iIGnvU.jpg",
            "http://imageshack.com/a/img922/3748/XvWQPz.jpg",
            "http://imageshack.com/a/img922/2177/gm9ddy.jpg",
            "http://imageshack.com/a/img924/7344/JBqVbQ.jpg")));
        profileList.add(create(6, "Đào", 22, Arrays.asList(
            "http://imageshack.com/a/img924/6515/JiylGo.jpg",
            "http://imageshack.com/a/img924/6537/AfNnra.jpg",
            "http://imageshack.com/a/img924/802/rBCWs3.jpg",
            "http://imageshack.com/a/img923/9322/bO0hYw.jpg",
            "http://imageshack.com/a/img923/7392/kyiKsh.jpg")));
        profileList.add(create(7, "Đào", 22, Arrays.asList(
            "http://imageshack.com/a/img924/9423/E8Xxky.jpg",
            "http://imageshack.com/a/img922/8366/7TVQZk.jpg",
            "http://imageshack.com/a/img922/8117/3OJydD.jpg")));
        profileList.add(create(8, "Đào", 22, Arrays.asList(
            "http://imageshack.com/a/img923/6430/OK2kfH.jpg",
            "http://imageshack.com/a/img924/8688/j6RaJz.jpg",
            "http://imageshack.com/a/img924/7714/LWTaxv.jpg",
            "http://imageshack.com/a/img922/64/u9LXlR.jpg")));
        return profileList;
    }

    public static Profile create(int id, String name, int age, List<String> imageList) {
        return new Profile(id, name, age, imageList);
    }
}

1.4. ViewBindingAdapter

Function loadImage() để vẽ ảnh bằng picasso với link url đc truyền vào

package tuananh.com.slideimageinrecyclerview.view.binding;

import android.databinding.BindingAdapter;
import android.widget.ImageView;

import com.squareup.picasso.Picasso;

import tuananh.com.slideimageinrecyclerview.R;

/**
 * Created by framgia on 27/04/2017.
 */
public class ViewBindingAdapter {
    @BindingAdapter("imageUrl")
    public static void loadImage(ImageView imageView, String url) {
        Picasso.with(imageView.getContext())
            .load(url)
            .placeholder(R.drawable.image_default)
            .into(imageView);
    }
}

1.5. Interface OnClickShowImageListener

package tuananh.com.slideimageinrecyclerview.listener;

import tuananh.com.slideimageinrecyclerview.model.Profile;

/**
 * Created by TuanAnh on 4/28/2017.
 */
public interface OnClickShowImageListener {
    void onClickShowImage(Profile profile, int positionImage);
}

2. Adapter

2.1 SlideImageAdapter

2.1.1. SlideImageAdapter

Tạo Adapter cho slide image là SlideImageAdapter Hàm khởi tạo cần truyền profile và listener onClickShowImageListener ( mục đích là bắt sự kiện OnClickListener vào ảnh để sang trang show full image) public SlideImageAdapter(Context context, Profile profile, OnClickShowImageListener onClickShowImageListener) { }

package tuananh.com.slideimageinrecyclerview.view.adapter;

import android.content.Context;
import android.databinding.DataBindingUtil;
import android.support.v4.view.PagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

import tuananh.com.slideimageinrecyclerview.R;
import tuananh.com.slideimageinrecyclerview.databinding.FragmentSlideProfileBinding;
import tuananh.com.slideimageinrecyclerview.listener.OnClickShowImageListener;
import tuananh.com.slideimageinrecyclerview.model.Profile;

/**
 * Created by framgia on 27/04/2017.
 */
public class SlideImageAdapter extends PagerAdapter {
    private Context mContext;
    private List<String> mImageList;
    private LayoutInflater mLayoutInflater;
    private Profile mProfile;
    private OnClickShowImageListener mOnClickShowImageListener;

    public SlideImageAdapter(Context context, Profile profile,
                             OnClickShowImageListener onClickShowImageListener) {
        mContext = context;
        mProfile = profile;
        mImageList = profile.getImageList();
        mOnClickShowImageListener = onClickShowImageListener;
        mLayoutInflater = LayoutInflater.from(context);
    }

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

    @Override
    public int getCount() {
        return mImageList == null ? 0 : mImageList.size();
    }

    @Override
    public Object instantiateItem(ViewGroup container, final int position) {
        FragmentSlideProfileBinding binding = DataBindingUtil.inflate(mLayoutInflater,
            R.layout.fragment_slide_profile, container, false);
        binding.getRoot().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mOnClickShowImageListener != null) {
                    mOnClickShowImageListener.onClickShowImage(mProfile, position);
                }
            }
        });
        binding.setUrl(mImageList.get(position));
        binding.setPosition(position);
        binding.getRoot().setTag(position);
        container.addView(binding.getRoot(), 0);
        return binding.getRoot();
    }

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

2.1.2. Layout

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="position"
            type="int"/>

        <variable
            name="url"
            type="String"/>

    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white">

        <ImageView
            android:id="@+id/image_slide"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            app:imageUrl="@{url}"/>
    </FrameLayout>
</layout>

2.2. ProfileAdapter

2.2.1. Tạo adapter ProfileAdapter cho reycerview

Function public void bind(Profile profile) {}

  • mBinding.setVariable(BR.viewModel, profile); -> truyền data và trong layout
  • SlideImageAdapter slideImageAdapter = new SlideImageAdapter(mContext, profile, mOnClickShowImageListener); -> khởi tạo slideImageAdapter cho viewpager trong mỗi item của recyclerview
  • mBinding.slideImageViewPager.setAdapter(slideImageAdapter); -> truyền adapter vào viewpager
  • mBinding.slideImageViewPager.setOffscreenPageLimit(MAX_SIZE_IMAGE_LOAD); -> load tối đa MAX_SIZE_IMAGE_LOAD ảnh ban đầu
  • mBinding.indicator.setViewPager(mBinding.slideImageViewPager); -> truyền viewpager vào CircleIndicator để bắt sự kiện scroll viewpager
package tuananh.com.slideimageinrecyclerview.view.adapter;

import android.content.Context;
import android.databinding.DataBindingUtil;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;

import java.util.List;

import tuananh.com.slideimageinrecyclerview.BR;
import tuananh.com.slideimageinrecyclerview.R;
import tuananh.com.slideimageinrecyclerview.databinding.ItemRecyclerProfileBinding;
import tuananh.com.slideimageinrecyclerview.listener.OnClickShowImageListener;
import tuananh.com.slideimageinrecyclerview.model.Profile;

/**
 * Created by TuanAnh on 4/26/2017.
 */
public class ProfileAdapter extends RecyclerView.Adapter<ProfileAdapter.ProfileViewHolder> {
    private static final int MAX_SIZE_IMAGE_LOAD = 8;
    private Context mContext;
    private LayoutInflater mLayoutInflater;
    private List<Profile> mProfileList;
    private OnClickShowImageListener mOnClickShowImageListener;

    public ProfileAdapter(Context context, List<Profile> profileList,
                          OnClickShowImageListener onClickShowImageListener) {
        mContext = context;
        mProfileList = profileList;
        mOnClickShowImageListener = onClickShowImageListener;
        mLayoutInflater = LayoutInflater.from(context);
    }

    @Override
    public ProfileViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ItemRecyclerProfileBinding binding = DataBindingUtil.inflate(mLayoutInflater,
            R.layout.item_recycler_profile, parent, false);
        return new ProfileViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(ProfileViewHolder holder, int position) {
        Profile profile = mProfileList.get(position);
        holder.bind(profile);
    }

    @Override
    public int getItemCount() {
        return mProfileList == null ? 0 : mProfileList.size();
    }

    public class ProfileViewHolder extends RecyclerView.ViewHolder {
        private ItemRecyclerProfileBinding mBinding;

        public ProfileViewHolder(ItemRecyclerProfileBinding binding) {
            super(binding.getRoot());
            mBinding = binding;
        }

        public void bind(Profile profile) {
            mBinding.setVariable(BR.viewModel, profile);
            SlideImageAdapter slideImageAdapter =
                new SlideImageAdapter(mContext, profile, mOnClickShowImageListener);
            mBinding.sliderImageViewPager.setAdapter(slideImageAdapter);
            mBinding.sliderImageViewPager.setOffscreenPageLimit(MAX_SIZE_IMAGE_LOAD);
            mBinding.indicator.setViewPager(mBinding.sliderImageViewPager);
            mBinding.executePendingBindings();
        }
    }
}

2.2.2. Layout

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="viewModel"
            type="tuananh.com.slideimageinrecyclerview.model.Profile"/>

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/margin_padding_10"
            android:layout_marginLeft="@dimen/margin_padding_20"
            android:drawableLeft="@drawable/img_dots"
            android:drawablePadding="@dimen/margin_padding_10"
            android:text="@{viewModel.nameAge}"
            android:textSize="@dimen/text_size_14"
            android:textStyle="bold"/>

        <android.support.v4.view.ViewPager
            android:id="@+id/slide_image_view_pager"
            android:layout_width="match_parent"
            android:layout_height="@dimen/size_200"/>

        <tuananh.com.slideimageinrecyclerview.view.custom.CircleIndicator
            android:id="@+id/indicator"
            android:layout_width="match_parent"
            android:layout_height="@dimen/size_30"
            android:layout_gravity="bottom"
            app:ci_drawable="@drawable/black_radius"
            app:ci_drawable_unselected="@drawable/blur_radius"/>
    </LinearLayout>
</layout>

Image

Tham khảo

Code