Android Modern Image Slider using ViewPager 2 and KenBurnsView | Android Studio

In this tutorial, we will make a modern image slider using ViewPager2 in which we will implement a ken burns view to animate the image. Here we will use static data for the slider but you can use data from API as well.

The question is what is Ken Burns View effect? Let’s see what is Ken Burns effect

Ken Burns View

KenBurnsView provides the following advantages:

  • Control: you can change the duration and the interpolator of transitions and pause/resume them. You can also listen to events like onTransitionStart() and onTransitionEnd();
  • Highly extensible: you can define how the rectangles to be zoomed and panned will be generated;
  • Libs friendly: since KenBurnsView is a direct extension of ImageView, it seamlessly works out of the box with your favorite image loader library;
  • Easy to use: you can start using it right away. All you need to do is to drop the JAR file into your project and replace ImageView elements in your XML layout files by com.flaviofaria.kenburnsview.KenBurnsView ones.

Now let’s create a modern Image Slider using Viewpager

Gradle Integration

dependencies {
implementation 'com.google.android.material:material:1.3.0'
//Ppicasso- for image loading
implementation 'com.squareup.picasso:picasso:2.71828'
//Ken Burns view - for ken burns effect
implementation 'com.flaviofaria:kenburnsview:1.0.7'
//viewpager 2
implementation "androidx.viewpager2:viewpager2:1.0.0"
}
  • add maven repository in your build.gradle project folder
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}

Design the main view

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".ModernImageSlider.ModernImageSliderActivity">
<androidx.cardview.widget.CardView
android:layout_width="40dp"
android:layout_height="40dp"
android:id="@+id/cardProfilePic"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
app:cardCornerRadius="20dp"
app:cardElevation="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/app_name"
android:src="@drawable/profile_pic"
android:scaleType="fitXY"/>
</androidx.cardview.widget.CardView> <TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/textHello"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:text="@string/hello_android"
android:textColor="#212121"
android:textSize="17sp"
android:fontFamily="@font/product_sans_bold"
app:layout_constraintBottom_toBottomOf="@id/cardProfilePic"
app:layout_constraintEnd_toStartOf="@id/cardProfilePic"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/cardProfilePic"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textWhereAreWe"
android:text="@string/seven_wonders"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:textColor="#212121"
android:textSize="35sp"
android:fontFamily="@font/antonio_bold"
android:includeFontPadding="false"
app:layout_constraintTop_toBottomOf="@id/cardProfilePic"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textGoing"
android:text="@string/of_the_world"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:textColor="#757575"
android:textSize="30sp"
android:includeFontPadding="false"
android:fontFamily="@font/antonio_bold"
app:layout_constraintTop_toBottomOf="@id/textWhereAreWe"/>
<androidx.viewpager2.widget.ViewPager2
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="@+id/locationViewPager"
android:layout_marginTop="30dp"
android:layout_marginBottom="30dp"
android:paddingStart="40dp"
android:paddingEnd="40dp"
app:layout_constraintBottom_toTopOf="@id/bottomText"
app:layout_constraintTop_toBottomOf="@id/textGoing"/>
<TextView
android:layout_width="match_parent"
android:layout_height="70dp"
android:id="@+id/bottomText"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:gravity="center"
android:text="@string/do_you_find_it_helpful"
android:fontFamily="@font/product_sans_bold"
android:textColor="#212121"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

Design Viewpager item

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_margin="5dp"
app:cardCornerRadius="12dp"
app:cardElevation="5dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.flaviofaria.kenburnsview.KenBurnsView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/kbvLocation"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:background="@drawable/background_star_rating"
android:gravity="center_vertical"
android:paddingStart="8dp"
android:paddingTop="2dp"
android:paddingEnd="8dp"
android:paddingBottom="2dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="16dp"
android:layout_height="16sp"
android:contentDescription="@string/app_name"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:src="@drawable/ic_baseline_star_24"
app:tint="#FFFFFF" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textStartRating"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:textColor="#FFFFFF"
android:textSize="15sp"/>
</LinearLayout> <View
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#D6000000"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="@id/textTitle"/>
<ImageView
android:layout_width="18sp"
android:layout_height="18sp"
android:id="@+id/imageLocation"
android:layout_marginStart="20dp"
android:contentDescription="@string/app_name"
android:src="@drawable/ic_baseline_location_on_24"
app:tint="#FFFFFF"
app:layout_constraintBottom_toBottomOf="@id/textLocation"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/textLocation"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/textLocation"
android:layout_marginStart="2dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="8dp"
android:textColor="#FFFFFF"
android:textSize="14sp"
android:fontFamily="@font/antonio_bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/imageLocation"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textTitle"
android:layout_marginStart="20dp"
android:layout_marginBottom="2dp"
android:layout_marginEnd="20dp"
android:paddingTop="4dp"
android:textColor="#FFFFFF"
android:textSize="19sp"
android:fontFamily="@font/antonio_bold"
app:layout_constraintBottom_toTopOf="@id/imageLocation"/>
</androidx.constraintlayout.widget.ConstraintLayout></androidx.cardview.widget.CardView>

you can change it according to your needs.

Create a model class

package com.codewithgolap.androidtutorial.ModernImageSlider;public class TravelLocation {    public String title, location, imageUrl;
public Float startRating;
}

Create an adapter

package com.codewithgolap.androidtutorial.ModernImageSlider;import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.codewithgolap.androidtutorial.R;
import com.flaviofaria.kenburnsview.KenBurnsView;
import com.squareup.picasso.Picasso;
import java.util.List;public class TravelLocationAdapter extends RecyclerView.Adapter<TravelLocationAdapter.TravelLocationViewHolder>{ private List<TravelLocation> travelLocations; public TravelLocationAdapter(List<TravelLocation> travelLocations) {
this.travelLocations = travelLocations;
}
@NonNull
@Override
public TravelLocationViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new TravelLocationViewHolder(
LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_container_location,
parent, false
)
);
}
@Override
public void onBindViewHolder(@NonNull TravelLocationViewHolder holder, int position) {
holder.setLocationData(travelLocations.get(position));
}
@Override
public int getItemCount() {
return travelLocations.size();
}
static class TravelLocationViewHolder extends RecyclerView.ViewHolder { private KenBurnsView kbvLocation;
private TextView textTitle, textLocation, textStartRating;
TravelLocationViewHolder(@NonNull View itemView) {
super(itemView);
kbvLocation = itemView.findViewById(R.id.kbvLocation);
textTitle = itemView.findViewById(R.id.textTitle);
textStartRating = itemView.findViewById(R.id.textStartRating);
textLocation = itemView.findViewById(R.id.textLocation);
}
void setLocationData(TravelLocation travelLocation){
Picasso.get().load(travelLocation.imageUrl).into(kbvLocation);
textTitle.setText(travelLocation.title);
textLocation.setText(travelLocation.location);
textStartRating.setText(String.valueOf(travelLocation.startRating));
}
}
}

Add functionality

package com.codewithgolap.androidtutorial.ModernImageSlider;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.CompositePageTransformer;
import androidx.viewpager2.widget.MarginPageTransformer;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import android.view.View;
import com.codewithgolap.androidtutorial.R;import java.util.ArrayList;
import java.util.List;
public class ModernImageSliderActivity extends AppCompatActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_modern_image_slider);
ViewPager2 locationViewPager = findViewById(R.id.locationViewPager); List<TravelLocation> travelLocations = new ArrayList<>(); TravelLocation travelLocationET = new TravelLocation();
travelLocationET.imageUrl = "https://images.unsplash.com/photo-1500297726361-1715d90aec00?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1047&q=80";
travelLocationET.title = "China";
travelLocationET.location = "Grate Wall of China";
travelLocationET.startRating = 4.8f;
travelLocations.add(travelLocationET);
TravelLocation travelLocationMV = new TravelLocation();
travelLocationMV.imageUrl = "https://images.unsplash.com/photo-1567930009485-07d60c813306?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80";
travelLocationMV.title = "Mexico";
travelLocationMV.location = "Chichén Itzá";
travelLocationMV.startRating = 4.5f;
travelLocations.add(travelLocationMV);
TravelLocation travelLocationTM = new TravelLocation();
travelLocationTM.imageUrl = "https://images.unsplash.com/photo-1589825274556-94746a018766?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80";
travelLocationTM.title = "Jordan";
travelLocationTM.location = "Petra";
travelLocationTM.startRating = 4.7f;
travelLocations.add(travelLocationTM);
TravelLocation travelLocationF = new TravelLocation();
travelLocationF.imageUrl = "https://images.unsplash.com/photo-1456244440184-1d494704a505?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80";
travelLocationF.title = "Peru";
travelLocationF.location = "Machu Picchu";
travelLocationF.startRating = 4.6f;
travelLocations.add(travelLocationF);
TravelLocation travelLocationFi = new TravelLocation();
travelLocationFi.imageUrl = "https://images.unsplash.com/photo-1595688878177-b72dfeeed683?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1151&q=80";
travelLocationFi.title = "Brazil";
travelLocationFi.location = "Christ the Redeemer";
travelLocationFi.startRating = 4.6f;
travelLocations.add(travelLocationFi);
TravelLocation travelLocationS = new TravelLocation();
travelLocationS.imageUrl = "https://images.unsplash.com/photo-1482401204742-eb3c31c24722?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1112&q=80";
travelLocationS.title = "Italy";
travelLocationS.location = "Colosseum";
travelLocationS.startRating = 4.7f;
travelLocations.add(travelLocationS);
TravelLocation travelLocationSe = new TravelLocation();
travelLocationSe.imageUrl = "https://images.unsplash.com/photo-1524492412937-b28074a5d7da?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1051&q=80";
travelLocationSe.title = "India";
travelLocationSe.location = "Taj Mahal";
travelLocationSe.startRating = 4.8f;
travelLocations.add(travelLocationSe);
locationViewPager.setAdapter(new TravelLocationAdapter(travelLocations)); locationViewPager.setClipToPadding(false);
locationViewPager.setClipChildren(false);
locationViewPager.setOffscreenPageLimit(3);
locationViewPager.getChildAt(0).setOverScrollMode(RecyclerView.OVER_SCROLL_NEVER);
CompositePageTransformer compositePageTransformer = new CompositePageTransformer();
compositePageTransformer.addTransformer(new MarginPageTransformer(40));
compositePageTransformer.addTransformer(new ViewPager2.PageTransformer() {
@Override
public void transformPage(@NonNull View page, float position) {
float r = 1 - Math.abs(position);
page.setScaleY(0.90f + r * 0.04f);
}
});
locationViewPager.setPageTransformer(compositePageTransformer);
}
}

Output

Follow me on IG at @androidapps.development.blogs

Hi everyone, myself Golap an Android app developer with UI/UX designer.