Howtodoandroid
Published in

Howtodoandroid

Swipeable cardview android example

In this tutorial, we will develop views and architecture to simulate the Swipe card view in android. using PlaceHolderView.

Set up the project in the android studio.

In app’s build.gradle add the dependencies like Retrofit, Recyclerview, glide etc.

dependencies {
compile 'com.mindorks:placeholderview:0.7.2'
implementation 'com.android.support:recyclerview-v7:27.0.2'
implementation 'com.android.support:cardview-v7:27.0.2'
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.github.bumptech.glide:glide:4.6.1'
}

Add Internet permission in the app’s AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>

Step 2

setup the layouts.

  1. Add PlaceHolderView into your main activity layout.
    activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:padding="20dp"
android:background="#717171"
tools:context=".MainActivity">

<Button
android:id="@+id/button_selected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:padding="10dp"
android:text="selected"
android:background="#7bc741"
android:textColor="@android:color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/button_rejected"
app:layout_constraintTop_toBottomOf="@+id/swipePlaceHolder"/>

<Button
android:id="@+id/button_rejected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_marginTop="8dp"
android:layout_marginStart="16dp"
android:text="Rejected"
android:background="#ff5252"
android:textColor="@android:color/white"
app:layout_constraintEnd_toStartOf="@+id/button_selected"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/swipePlaceHolder"/>

<com.mindorks.placeholderview.SwipePlaceHolderView
android:id="@+id/swipePlaceHolder"
android:layout_width="300dp"
android:layout_height="300dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</com.mindorks.placeholderview.SwipePlaceHolderView>
</android.support.constraint.ConstraintLayout>

2. Add layout for the Swipecard view.
swipecardview_layout.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="match_parent">

<ImageView
android:id="@+id/imageView"
android:layout_width="300dp"
android:layout_height="300dp"
android:background="@drawable/ic_launcher_background"
android:scaleType="centerCrop"/>

<TextView
android:id="@+id/textview_name"
android:layout_width="300dp"
android:layout_height="40dp"
android:layout_gravity="bottom"
android:background="#b1b0b0"
android:gravity="center"
android:textColor="@android:color/white"
android:text="Hello World" />
</FrameLayout>

3. Add a separate view for swipe in view and swipe out views. swipe_in_layout will appear when you start swipe in.

swipe_in_layout.xml

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

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/holo_green_dark"
android:textStyle="bold"
android:textSize="25sp"
android:text="Selected"/>

</LinearLayout>

swipe_out_layout will appear when you start swipe out.

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

<TextView
android:layout_width="match_parent"
android:layout_height="40dp"
android:textColor="@android:color/holo_red_dark"
android:textStyle="bold"
android:textSize="25sp"
android:text="Rejected"/>

</LinearLayout>

Step 3

Setup an HTTP client for Android. In this tutorial, I am using Retrofit. Please check my detailed post about Retrofit.

  1. setup Retrofit instance.
    ApiClient.java
public class ApiClient {

private static String BASE_URL="http://www.mocky.io/v2/";

private static Retrofit retrofit;

public static Retrofit getInstance(){
if(retrofit == null){
retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}

2. creating an API interface.
ApiInterface.java

public interface ApiInterface {

@GET("5a8fefef3000004f00248c70")
Call<List<Movie>> getAllMovies();
}

3. movie model.
Movie.java

public class Movie {

@SerializedName("name")
private String name;
@SerializedName("desc")
private String desc;

public String getImageUrl() {
return imageUrl;
}

public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}

@SerializedName("imageUrl")
private String imageUrl;

public Movie(String name, String desc, String image) {
this.name = name;
this.desc = desc;
this.imageUrl = image;
}

public String getName() {
return name;
}

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

public String getDesc() {
return desc;
}

public void setDesc(String desc) {
this.desc = desc;
}

@Override
public String toString() {
return "Movie{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
", image=" + imageUrl +
'}';
}
}

4. JSON Response for the API I am using http://www.mocky.io/v2/5a8fefef3000004f00248c70.

[
{
name: "Johnny Depp",
desc: "Pirates of the Caribbean",
imageUrl: "http://ia.media-imdb.com/images/M/MV5BMTM0ODU5Nzk2OV5BMl5BanBnXkFtZTcwMzI2ODgyNQ@@._V1_UY317_CR4,0,214,317_AL_.jpg"
},
{
name: "Arnold Schwarzenegger",
desc: "The Terminator",
imageUrl: "http://ia.media-imdb.com/images/M/MV5BMTI3MDc4NzUyMV5BMl5BanBnXkFtZTcwMTQyMTc5MQ@@._V1._SY209_CR13,0,140,209_.jpg"
},
{
name: "Johnny Depp",
desc: "Pirates of the Caribbean",
imageUrl: "http://ia.media-imdb.com/images/M/MV5BMTM0ODU5Nzk2OV5BMl5BanBnXkFtZTcwMzI2ODgyNQ@@._V1_UY317_CR4,0,214,317_AL_.jpg"
},
{
name: "Arnold Schwarzenegger",
desc: "The Terminator",
imageUrl: "http://ia.media-imdb.com/images/M/MV5BMTI3MDc4NzUyMV5BMl5BanBnXkFtZTcwMTQyMTc5MQ@@._V1._SY209_CR13,0,140,209_.jpg"
},
{
name: "Johnny Depp",
desc: "Pirates of the Caribbean",
imageUrl: "http://ia.media-imdb.com/images/M/MV5BMTM0ODU5Nzk2OV5BMl5BanBnXkFtZTcwMzI2ODgyNQ@@._V1_UY317_CR4,0,214,317_AL_.jpg"
},
{
name: "Arnold Schwarzenegger",
desc: "The Terminator",
imageUrl: "http://ia.media-imdb.com/images/M/MV5BMTI3MDc4NzUyMV5BMl5BanBnXkFtZTcwMTQyMTc5MQ@@._V1._SY209_CR13,0,140,209_.jpg"
},
{
name: "Johnny Depp",
desc: "Pirates of the Caribbean",
imageUrl: "http://ia.media-imdb.com/images/M/MV5BMTM0ODU5Nzk2OV5BMl5BanBnXkFtZTcwMzI2ODgyNQ@@._V1_UY317_CR4,0,214,317_AL_.jpg"
},
{
name: "Arnold Schwarzenegger",
desc: "The Terminator",
imageUrl: "http://ia.media-imdb.com/images/M/MV5BMTI3MDc4NzUyMV5BMl5BanBnXkFtZTcwMTQyMTc5MQ@@._V1._SY209_CR13,0,140,209_.jpg"
}
]

Step 4

setup the swipe card view.

  1. initialise and setup placeholder view in your MainActivity.java. Also, Add swipe in layout and swipe out layouts.
private SwipePlaceHolderView swipePlaceHolderView;

swipePlaceHolderView = findViewById(R.id.swipePlaceHolder);

swipePlaceHolderView.getBuilder().setDisplayViewCount(3)
.setSwipeDecor(new SwipeDecor().setPaddingTop(20)
.setRelativeScale(0.01f).setSwipeInMsgLayoutId(R.layout.swipe_in_layout)
.setSwipeOutMsgLayoutId(R.layout.swipe_out_layout));

2. Once initialize the SwipePlaceHolderView, then load the data from the API and create swipecard view. That swipecard view needs to be added in SwipePlaceHolderView.

private void loadData() {

ApiInterface apiInterface = ApiClient.getInstance().create(ApiInterface.class);
apiInterface.getAllMovies().enqueue(new Callback<List<Movie>>() {
@Override
public void onResponse(Call<List<Movie>> call, Response<List<Movie>> response) {
movieList = response.body();
for (Movie movie : movieList){
swipePlaceHolderView.addView(new SwipeCardView(context,swipePlaceHolderView,movie));
}
}

@Override
public void onFailure(Call<List<Movie>> call, Throwable t) {
Log.d("Movielist",t.getMessage());
}
});
}

3. SwipeCardView.java

@Layout(R.layout.swiprcardview_layout)
public class SwipeCardView {

private SwipeCardCallback swipecardCallback;
public static String TAG ="SwipeCardView";

@View(R.id.imageView)
private ImageView imageView;
@View(R.id.textview_name)
private TextView textViewName;
private Movie mMovie;
private Context mContext;
private SwipePlaceHolderView mSwipePlaceHolderView;
public SwipeCardView(Context context, SwipePlaceHolderView swipePlaceHolderView, Movie movie) {
this.mContext = context;
this.swipecardCallback = (SwipeCardCallback) context;
this.mSwipePlaceHolderView = swipePlaceHolderView;
this.mMovie = movie;
}

@Resolve
private void onResolve(){
Glide.with(mContext).load(mMovie.getImageUrl()).apply(RequestOptions.centerCropTransform()).into(imageView);
textViewName.setText(mMovie.getName());
}

@SwipeIn
private void onSwipeIn(){
swipecardCallback.onSwipeIn();
}

@SwipeOut
private void onSwipeOut(){
swipecardCallback.onSwipeOut();
}

}

Here,

@layout is used to bind the layout with this class.

@View is used to bind the views in a layout we want to refer to.

@Resolve annotation bind a method to be executed when the view is ready to be used. Any operation we want to perform on view references should be written in a method and annotated with this.

@SwipeOut calls the annotated method when the card has been rejected.

@SwipeIn calls the annotated method when the card has been accepted.

4. The callback of the swipe event to MainActivity.

public interface SwipeCardCallback {
void onSwipeIn();
void onSwipeOut();
}

5. Implement the callback in your MainActivity,

public class MainActivity extends AppCompatActivity implements SwipeCardSwipeCallback{

@Override
public void onSwipeIn() {
selected = selected + 1;
buttonSelected.setText("Selected ("+selected+")");
}

@Override
public void onSwipeOut() {
rejected = rejected + 1;
buttonRejected.setText("Rejected ("+rejected+")");
}
}

Screenshot

Direct Download Example Here

Related Stories,

Originally published at velmm.com on July 11, 2018.

--

--

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
Velmurugan Murugesan

Lead Android Engineer @htcindia | @github contributor | Blog writer @howtodoandroid | Quick Learner