Cara Membuat Stepper Layout di Android

Yudi Setiawan 13 April 2017

Cara Membuat Stepper Layout di Android

Pengantar

Apa itu "Stepper Layout Android?". Bila Anda cari di google image maka, yang keluar adalah seperti berikut.

Stepper Layout Android in Google Image

Jadi, Stepper Layout ini hampir sama atau bahkan mirip seperti Timeline Layout yang pernah saya bahas Cara Membuat Timeline Layout di Android . Tapi, pada umumnya kalau timeline layout dipakai untuk orientation vertical sementara, stepper layout sering dipakai secara orientation horizontal. Berikut adalah beberapa contoh dari beberapa apps yang menggunakan stepper layout.

Example Stepper Layout apps 1
Example Stepper Layout apps 2

Jadi, pada kedua contoh apps diatas bisa Anda lihat bahwa modelnya itu sama yaitu, sama-sama orientation horizontal namun, dengan sedikit customize drawable dan widget yang dipakai pada stepper layout. Jadi, kesimpulannya adalah bahwa stepper layout merupakan layout yang menampilkan sebuah proses atau langkah (step) pada sebuah aplikasi android.

Contoh Sederhana

Berikut adalah contoh sederhana dari stepper layout yang akan kita buat pada tutorial ini.

Example Simple Stepper Layout

Jadi, pada stepper layout di atas sebenarnya hanya terdiri dari 2 widget yaitu, View dan Button. View dengan custom drawable sebanyak 13 dan Button hanya berjumlah 2 saja. Berikut adalah wireframe dari layout-nya.

Wireframe Example Simple Stepper Layout

Pada wireframe diatas bisa Anda lihat bahwa View saya beri tanda dengan warna berikut.

  • Orange merupakan View dengan custom drawable yang berbentuk bulat dengan status proses aktif sebanyak 3.
  • Ungu merupakan View dengan custom drawable yang berbentuk bulat dengan status proses nonaktif sebanyak 3.
  • Biru merupakan View yang berbentuk garis horizontal dengan status proses aktif sebanyak 2.
  • Merah merupakan View yang berbentuk garis horizontal dengan status proses nonaktif sebanyak 2.
  • Hijau merupakan View yang berbentuk rectangle yang memiliki background white sebanyak 3 yang berfungsi sebagai pemberi margin pada View yang berbentuk bulat.

Sedangkan, untuk warna hitam itu merupakan Button biasa.

Mulai Pembuatan Contoh Projek Sederhana

Ada beberapa hal yang perlu Anda persiapkan pada tutorial ini yaitu sebagai berikut.

Pembuatan Projek

Silakan buka aplikasi Android Studio dan buat projek baru dengan nama Codepolitan - Example Stepper Layout dan pada bagian Activity pilih Empty Activity.

Custom Drawable

Silakan Anda buat 2 buah file di direktori res-drawable dengan nama background_circle_on.xml dan background_circle_off.xml. Pada file background_circle_on.xml, silakan Anda isi dengan kode program berikut.

<?xml version="1.0" encoding="utf-8"?>
<selector
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <item>
        <shape
            android:shape="oval"
            >
            <solid
                android:color="@color/colorPrimary"
                />
        </shape>
    </item>
</selector>

Selanjutnya, pada file background_circle_off.xml isi dengan kode program berikut.

<?xml version="1.0" encoding="utf-8"?>
<selector
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <item>
        <shape
            android:shape="oval"
            >
            <solid
                android:color="@android:color/darker_gray"
                />
        </shape>
    </item>
</selector>

Fungsi kedua file diatas adalah untuk dijadikan sebagai background dari View yang akan dibuat menjadi bulat.

activity_main.xml

Pada file layout, silakan Anda isi dengan kode program berikut.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingTop="@dimen/activity_vertical_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:background="@android:color/white"
    tools:context="com.ysn.codepolitan_examplestepperlayout.MainActivity"
    >

    <!--step 1 start-->
    <View
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:id="@+id/view_circle_on_1"
        android:background="@drawable/background_circle_on"
        android:layout_centerVertical="true"
        android:layout_marginRight="@dimen/activity_horizontal_margin"
        android:layout_marginEnd="@dimen/activity_horizontal_margin"
        />

    <View
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:id="@+id/view_circle_off_1"
        android:background="@drawable/background_circle_off"
        android:layout_centerVertical="true"
        android:layout_marginRight="@dimen/activity_horizontal_margin"
        android:layout_marginEnd="@dimen/activity_horizontal_margin"
        />

    <View
        android:layout_width="wrap_content"
        android:layout_height="2dp"
        android:id="@+id/view_horizontal_on_1"
        android:background="@color/colorPrimary"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/view_circle_on_1"
        android:layout_toEndOf="@+id/view_circle_on_1"
        android:layout_toLeftOf="@+id/view_circle_on_2"
        android:layout_toStartOf="@+id/view_circle_on_2"
        />

    <View
        android:layout_width="wrap_content"
        android:layout_height="2dp"
        android:id="@+id/view_horizontal_off_1"
        android:background="@android:color/darker_gray"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/view_circle_off_1"
        android:layout_toEndOf="@+id/view_circle_off_1"
        android:layout_toLeftOf="@+id/view_circle_off_2"
        android:layout_toStartOf="@+id/view_circle_off_2"
        />
    <!--step 1 end-->

    <!--step 2 start-->
    <View
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:id="@+id/view_circle_on_2"
        android:background="@drawable/background_circle_on"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        />

    <View
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:id="@+id/view_circle_off_2"
        android:background="@drawable/background_circle_off"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        />

    <View
        android:layout_width="wrap_content"
        android:layout_height="2dp"
        android:id="@+id/view_horizontal_on_2"
        android:background="@color/colorPrimary"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/view_circle_on_2"
        android:layout_toEndOf="@+id/view_circle_on_2"
        android:layout_toLeftOf="@+id/view_circle_on_3"
        android:layout_toStartOf="@+id/view_circle_on_3"
        />

    <View
        android:layout_width="wrap_content"
        android:layout_height="2dp"
        android:id="@+id/view_horizontal_off_2"
        android:background="@android:color/darker_gray"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/view_circle_off_2"
        android:layout_toEndOf="@+id/view_circle_off_2"
        android:layout_toLeftOf="@+id/view_circle_off_3"
        android:layout_toStartOf="@+id/view_circle_off_3"
        />

    <View
        android:layout_width="@dimen/activity_horizontal_margin"
        android:layout_height="36dp"
        android:background="@android:color/white"
        android:layout_centerVertical="true"
        android:layout_toLeftOf="@+id/view_circle_off_2"
        android:layout_toStartOf="@+id/view_circle_off_2"
        />

    <View
        android:layout_width="@dimen/activity_horizontal_margin"
        android:layout_height="36dp"
        android:background="@android:color/white"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/view_circle_off_2"
        android:layout_toEndOf="@+id/view_circle_off_2"
        />
    <!--step 2 end-->

    <!--step 3 start-->
    <View
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:id="@+id/view_circle_on_3"
        android:background="@drawable/background_circle_on"
        android:layout_centerVertical="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        />

    <View
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:id="@+id/view_circle_off_3"
        android:background="@drawable/background_circle_off"
        android:layout_centerVertical="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        />

    <View
        android:layout_width="@dimen/activity_horizontal_margin"
        android:layout_height="36dp"
        android:background="@android:color/white"
        android:layout_centerVertical="true"
        android:layout_toLeftOf="@+id/view_circle_on_3"
        android:layout_toStartOf="@+id/view_circle_on_3"
        />
    <!--step 3 end-->

    <!--action-->
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/button_next"
        android:text="Next"
        android:layout_below="@+id/view_circle_off_1"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/button_previous"
        android:text="Previous"
        android:layout_below="@+id/view_circle_off_1"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        />

</RelativeLayout>

Pada layout diatas kita menggunakan RelativeLayout sebagai container dan bisa Anda lihat bahwa kita hanya menggunakan 2 jenis widget yaitu, View dan Button.

ActivityMain.java

Pada file java, silakan isi dengan kode program berikut.

package com.ysn.codepolitan_examplestepperlayout;

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private View viewCircle1On, viewCircle1Off;
    private View viewHorizontal1On, viewHorizontal1Off;
    private View viewCircle2On, viewCircle2Off;
    private View viewHorizontal2On, viewHorizontal2Off;
    private View viewCircle3On, viewCircle3Off;
    private Button buttonNext, buttonPrevious;
    private int position = 0;
    private int widthView = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        loadComponent();
    }

    private void loadComponent() {
        viewCircle1On = (View) findViewById(R.id.view_circle_on_1);
        viewCircle1Off = (View) findViewById(R.id.view_circle_off_1);
        viewHorizontal1On = (View) findViewById(R.id.view_horizontal_on_1);
        viewHorizontal1Off = (View) findViewById(R.id.view_horizontal_off_1);
        viewCircle2On = (View) findViewById(R.id.view_circle_on_2);
        viewCircle2Off = (View) findViewById(R.id.view_circle_off_2);
        viewHorizontal2On = (View) findViewById(R.id.view_horizontal_on_2);
        viewHorizontal2Off = (View) findViewById(R.id.view_horizontal_off_2);
        viewCircle3On = (View) findViewById(R.id.view_circle_on_3);
        viewCircle3Off = (View) findViewById(R.id.view_circle_off_3);
        buttonNext = (Button) findViewById(R.id.button_next);
        buttonPrevious = (Button) findViewById(R.id.button_previous);

        viewHorizontal1Off.post(new Runnable() {
            @Override
            public void run() {
                widthView = viewHorizontal1Off.getWidth();
            }
        });

        buttonNext.setOnClickListener(this);
        buttonPrevious.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        if (view == buttonNext) {
            position++;
            if (position == 1) {
                ObjectAnimator objectAnimatorCircle1 = ObjectAnimator.ofFloat(viewCircle1Off, "alpha", 1, 0);
                objectAnimatorCircle1.setDuration(500);
                objectAnimatorCircle1.start();
            } else if (position == 2) {
                ObjectAnimator objectAnimatorHorizontal1 = ObjectAnimator.ofFloat(viewHorizontal1Off, "translationX", 0, widthView);
                objectAnimatorHorizontal1.setDuration(500);
                objectAnimatorHorizontal1.addListener(new Animator.AnimatorListener() {
                    @Override
                    public void onAnimationStart(Animator animator) {

                    }

                    @Override
                    public void onAnimationEnd(Animator animator) {
                        ObjectAnimator objectAnimatorCircle2 = ObjectAnimator.ofFloat(viewCircle2Off, "alpha", 1, 0);
                        objectAnimatorCircle2.setDuration(500);
                        objectAnimatorCircle2.start();
                    }

                    @Override
                    public void onAnimationCancel(Animator animator) {

                    }

                    @Override
                    public void onAnimationRepeat(Animator animator) {

                    }
                });
                objectAnimatorHorizontal1.start();
            } else if (position == 3) {
                ObjectAnimator objectAnimatorHorizontal2 = ObjectAnimator.ofFloat(viewHorizontal2Off, "translationX", 0, widthView);
                objectAnimatorHorizontal2.setDuration(500);
                objectAnimatorHorizontal2.addListener(new Animator.AnimatorListener() {
                    @Override
                    public void onAnimationStart(Animator animator) {

                    }

                    @Override
                    public void onAnimationEnd(Animator animator) {
                        ObjectAnimator objectAnimatorCircle3 = ObjectAnimator.ofFloat(viewCircle3Off, "alpha", 1, 0);
                        objectAnimatorCircle3.setDuration(500);
                        objectAnimatorCircle3.start();
                    }

                    @Override
                    public void onAnimationCancel(Animator animator) {

                    }

                    @Override
                    public void onAnimationRepeat(Animator animator) {

                    }
                });
                objectAnimatorHorizontal2.start();
            } else {
                position = 3;
            }
        } else if (view == buttonPrevious) {
            position--;
            if (position == 0) {
                ObjectAnimator objectAnimatorCircle1 = ObjectAnimator.ofFloat(viewCircle1Off, "alpha", 0, 1);
                objectAnimatorCircle1.setDuration(500);
                objectAnimatorCircle1.start();
            } else if (position == 1) {
                ObjectAnimator objectAnimatorCircle2 = ObjectAnimator.ofFloat(viewCircle2Off, "alpha", 0, 1);
                objectAnimatorCircle2.setDuration(500);
                objectAnimatorCircle2.addListener(new Animator.AnimatorListener() {
                    @Override
                    public void onAnimationStart(Animator animator) {

                    }

                    @Override
                    public void onAnimationEnd(Animator animator) {
                        ObjectAnimator objectAnimatorHorizontal1 = ObjectAnimator.ofFloat(viewHorizontal1Off, "translationX", widthView, 0);
                        objectAnimatorHorizontal1.setDuration(500);
                        objectAnimatorHorizontal1.start();
                    }

                    @Override
                    public void onAnimationCancel(Animator animator) {

                    }

                    @Override
                    public void onAnimationRepeat(Animator animator) {

                    }
                });
                objectAnimatorCircle2.start();
            } else if (position == 2) {
                final ObjectAnimator objectAnimatorCircle3 = ObjectAnimator.ofFloat(viewCircle3Off, "alpha", 0, 1);
                objectAnimatorCircle3.setDuration(500);
                objectAnimatorCircle3.addListener(new Animator.AnimatorListener() {
                    @Override
                    public void onAnimationStart(Animator animator) {

                    }

                    @Override
                    public void onAnimationEnd(Animator animator) {
                        ObjectAnimator objectAnimatorHorizontal2 = ObjectAnimator.ofFloat(viewHorizontal2Off, "translationX", widthView, 0);
                        objectAnimatorHorizontal2.setDuration(500);
                        objectAnimatorHorizontal2.start();
                    }

                    @Override
                    public void onAnimationCancel(Animator animator) {

                    }

                    @Override
                    public void onAnimationRepeat(Animator animator) {

                    }
                });
                objectAnimatorCircle3.start();
            } else {
                position = 0;
            }
        }
    }
}

Pada java, kita hanya memberikan sedikit logic sederhana untuk perpindahan stepper layout-nya dan ObjectAnimator untuk membuat proses perpindahan antar Stepper-nya menjadi lebih nyaman dilihat dengan efek alpha dan translationX. Dan sekarang silakan Anda compile maka, hasilnya akan sama seperti pada gambar sebelumnya. Dan jika Anda bisa mengembangkannya lagi maka, kurang lebih seperti inilah tampilannya.

Example Stepper Layout

Dan untuk projeknya bisa Anda lihat di github