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

Android library that provides an extension to ImageView that creates an immersive experience by animating it’s drawable using the Ken Burns Effect.

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();

Now let’s create a modern Image Slider using Viewpager

Gradle Integration

  • add these dependencies in your build.gradle app folder
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

now in the main XML file create your design and add the view pager.

<?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

  • now create a new Layout Resource File in the layout folder for the item contents of the view pager, where we add our ken burns effect for the images.
<?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

now create a model class for the items data we’re going to set in the adapter class. For that create a new java file in your package.

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

Create an adapter

Now create an adapter class for your item layout that we need to inflate.

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

now in the main java file, add your view pager and create a list of the model class to add the static data. Here we use static data.

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.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store