Android Carousel View using ViewPager
This post is a demo for creating a carousel in android by using ViewPager. It involves ViewPager of course, as well as custom compound view, drawable selector xml, ViewPager adapter and Fragment. Some improvement to this would be to add custom animation to the ViewPager and adjust the ViewPager sliding speed.
1. view_pager_carousel_view.xml, the layout for the carousel view. It has a ViewPager for holding the views in the carousel, and a LinearLayout for holding the view indicators in the carousel.
[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<android.support.v4.view.ViewPager
android:id="@+id/vp_carousel"
android:layout_width="match_parent"
android:layout_height="200dp"/>
<LinearLayout
android:id="@+id/ll_page_indicator_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="center_horizontal"
android:layout_alignBottom="@+id/vp_carousel"
android:layout_marginBottom="10dp"
android:orientation="horizontal"/>
</merge>
[/code]
2. selector_carousel_page_indicator.xml, the drawable for the carousel indicators, those little bullets/circles at the bottom on the carousel view. Dark color when selected, gray when not.
[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" >
<shape android:shape="oval">
<solid android:color="@android:color/background_dark" />
<size android:width="6dp" android:height="6dp" />
</shape>
</item>
<item>
<shape android:shape="oval">
<solid android:color="@android:color/darker_gray" />
<size android:width="6dp" android:height="6dp" />
</shape>
</item>
</selector>
[/code]
3. view_pager_carousel_fragment.xml, the layout for each individual view in the carousel. For demo puporse, there is only an image in it.
[code language=”java”]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_carousel_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
</LinearLayout>
[/code]
4. ViewPagerCarouselFragment.java, the Fragment class for the each individual view in the carousel.
[code language=”java”]
public class ViewPagerCarouselFragment extends Fragment {
public static final String IMAGE_RESOURCE_ID = "image_resource_id";
private ImageView ivCarouselImage;
private int imageResourceId;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.view_pager_carousel_fragment, container, false);
ivCarouselImage = (ImageView) v.findViewById(R.id.iv_carousel_image);
imageResourceId = getArguments().getInt(IMAGE_RESOURCE_ID, R.drawable.car1); // default to car1 image resource
ivCarouselImage.setImageResource(imageResourceId);
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getContext(), "image: " + imageResourceId, Toast.LENGTH_SHORT).show();
}
});
return v;
}
}
[/code]
5. ViewPagerCarouselAdapter.java, the adapter for the ViewPager.
[code language=”java”]
public class ViewPagerCarouselAdapter extends FragmentStatePagerAdapter {
private int[] imageResourceIds;
public ViewPagerCarouselAdapter(FragmentManager fm, int[] imageResourceIds) {
super(fm);
this.imageResourceIds = imageResourceIds;
}
@Override
public Fragment getItem(int position) {
Bundle bundle = new Bundle();
bundle.putInt(ViewPagerCarouselFragment.IMAGE_RESOURCE_ID, imageResourceIds[position]);
ViewPagerCarouselFragment frag = new ViewPagerCarouselFragment();
frag.setArguments(bundle);
return frag;
}
@Override
public int getCount() {
return (imageResourceIds == null) ? 0: imageResourceIds.length;
}
}
[/code]
6. ViewPagerCarouselView.java, the compound view class for the carousel view. This class will be used to create for carousel view.
[code language=”java”]
public class ViewPagerCarouselView extends RelativeLayout {
private FragmentManager fragmentManager; // FragmentManager for managing the fragments withing the ViewPager
private ViewPager vpCarousel; // ViewPager for the Carousel view
private LinearLayout llPageIndicatorContainer; // Carousel view item indicator, the little bullets at the bottom of the carousel
private ArrayList<ImageView> carouselPageIndicators; // Carousel view item, the little bullet at the bottom of the carousel
private int [] imageResourceIds; // Carousel view background image
private long carouselSlideInterval; // Carousel view item sliding interval
private Handler carouselHandler; // Carousel view item sliding interval automation handler
public ViewPagerCarouselView (Context context) {
super(context);
initView(context);
}
public ViewPagerCarouselView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public ViewPagerCarouselView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView(context);
}
public void initView(Context context) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.view_pager_carousel_view, this);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
vpCarousel = (ViewPager) this.findViewById(R.id.vp_carousel);
llPageIndicatorContainer = (LinearLayout) this.findViewById(R.id.ll_page_indicator_container);
}
/**
* Set the data and initialize the carousel view
* @param fragmentManager
* @param imageResourceIds
* @param carouselSlideInterval
*/
public void setData(FragmentManager fragmentManager, int [] imageResourceIds, long carouselSlideInterval) {
this.fragmentManager = fragmentManager;
this.imageResourceIds = imageResourceIds;
this.carouselSlideInterval = carouselSlideInterval;
initData();
initCarousel();
initCarouselSlide();
}
/**
* Initialize the data for the carousel
*/
private void initData() {
carouselPageIndicators = new ArrayList<>();
for (int i = 0; i < imageResourceIds.length; i++) {
ImageView obj = new ImageView(getContext());
obj.setImageResource(R.drawable.selector_carousel_page_indicator);
obj.setPadding(0, 0, 5, 0); // left, top, right, bottom
llPageIndicatorContainer.addView(obj);
carouselPageIndicators.add(obj);
}
}
/**
* Initialize carousel views, each item in the carousel view is a fragment
*/
private void initCarousel() {
carouselPageIndicators.get(0).setSelected(true);
// Update the carousel page indicator on change
vpCarousel.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
for (int i = 0; i < carouselPageIndicators.size(); i++) {
if (i == position)
carouselPageIndicators.get(position).setSelected(true);
else
carouselPageIndicators.get(i).setSelected(false);
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
ViewPagerCarouselAdapter viewPagerCarouselAdapter = new ViewPagerCarouselAdapter(fragmentManager, imageResourceIds);
vpCarousel.setPageTransformer(false, new CustomViewPageTransformer(CustomViewPageTransformer.TransformType.SLIDE_OVER));
vpCarousel.setAdapter(viewPagerCarouselAdapter);
}
/**
* Handler to make the view pager to slide automatically
*/
private void initCarouselSlide() {
final int nCount = imageResourceIds.length;
try {
carouselHandler = new Handler();
carouselHandler.postDelayed(new Runnable() {
@Override
public void run() {
int curPos = vpCarousel.getCurrentItem();
curPos++;
if (curPos == nCount) curPos = 0;
vpCarousel.setCurrentItem(curPos, true);
carouselHandler.postDelayed(this, carouselSlideInterval);
}
}, carouselSlideInterval);
} catch (Exception e) {
Log.d("MainActivity", e.getMessage());
}
}
public void onDestroy() {
if (carouselHandler != null) carouselHandler.removeCallbacksAndMessages(null); // remove call backs to prevent memory leaks
}
}
[/code]
7. activity_main.xml, finally, we have all the things set up to support the carousel and we can use it in the layout file, just like how you would use other views such as ListView, RecyclerView, CardView, Button, TextView, etc.
[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.sample.viewpagercarousel.MainActivity">
<com.sample.viewpagercarousel.ViewPagerCarouselView
android:id="@+id/carousel_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"></com.sample.viewpagercarousel.ViewPagerCarouselView>
</RelativeLayout>
[/code]
8. MainActivity.java
MainActivity -> ViewPagerCarouselView -> ViewPagerCarouselAdapter -> ViewPagerCarouselFragment
[code language=”java”]
public class MainActivity extends AppCompatActivity {
ViewPagerCarouselView viewPagerCarouselView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
long carouselSlideInterval = 3000; // 3 SECONDS
int [] imageResourceIds = {R.drawable.car1, R.drawable.car2, R.drawable.car3, R.drawable.car4, R.drawable.car5, R.drawable.car6};
viewPagerCarouselView = (ViewPagerCarouselView) findViewById(R.id.carousel_view);
viewPagerCarouselView.setData(getSupportFragmentManager(), imageResourceIds, carouselSlideInterval);
}
@Override
protected void onDestroy() {
super.onDestroy();
viewPagerCarouselView.onDestroy();
}
}
[/code]
Search within Codexpedia

Search the entire web
