Advertisement
Scroll to top
Read Time: 12 min

() translation by (you can also view the original English article)

Ketika membuat aplikasi yang kompleks, Anda akan sering ingin menggunakan kembali kelompok view yang sama di berbagai tempat dari aplikasi. Salah satu cara untuk memecahkan masalah ini adalah dengan membuat sebuah view yang merangkum logika dan tata letak sekelompok view sehingga Anda dapat menggunakannya kembali tanpa menduplikasi kode di berbagai tempat dari proyek. Dalam tutorial ini, Anda akan belajar cara menggunakan view gabungan untuk membuat view kustom yang mudah digunakan kembali.

1. Perkenalan

Di Android, view yang terdiri dari sekelompok view disebut view gabungan atau komponen gabungan. Dalam tutorial ini, Anda akan membangun control untuk memilih nilai dari daftar yang bergulir dari sisi ke sisi. Kami akan menamakan gabungan tersebut sebagai side spinner karena tampilan default SDK Android untuk memilih nilai dari daftar disebut sebagai spinner. Tangkapan layar berikut mengilustrasikan apa yang akan kita buat dalam tutorial ini.

2. Pengaturan Proyek

Untuk memulai, Anda harus membuat proyek Android baru dengan Android 4.0 sebagai tingkat SDK minimum yang diperlukan. Proyek ini hanya boleh berisi activity kosong yang disebut MainActivity. Activity tidak melakukan apa-apa selain menginisialisasi layout seperti yang Anda lihat di cuplikan kode berikut.

1
public class MainActivity extends Activity {
2
   @Override
3
   protected void onCreate(Bundle savedInstanceState) {
4
      super.onCreate(savedInstanceState);
5
      setContentView(R.layout.activity_main);
6
   }
7
}

Layout untuk MainActivity terletak di file /res/layout/activity_main.xml dan seharusnya hanya berisi RelativeLayout kosong dimana view gabungan akan ditampilkan nantinya.

1
<RelativeLayout 
2
    xmlns:android="https://schemas.android.com/apk/res/android"
3
    xmlns:tools="http://schemas.android.com/tools"
4
    android:layout_width="match_parent"
5
    android:layout_height="match_parent"
6
    tools:context=".MainActivity">
7
</RelativeLayout>

3. Membuat sebuah View Gabungan

Untuk membuat view gabungan, Anda harus membuat kelas baru yang mengelola view dalam view gabungan. Untuk side spinner, Anda memerlukan dua view Button untuk panah dan view TextView untuk menampilkan nilai yang dipilih.

Untuk memulai, buat file layout /res/layout/sidespinner_view.xml yang akan kita gunakan untuk kelas side spinner, pastikan untuk membungkus tiga view dalam tag <merge>.

1
<merge xmlns:android="http://schemas.android.com/apk/res/android">
2
    <Button
3
        android:id="@+id/sidespinner_view_previous"
4
        android:layout_width="wrap_content"
5
        android:layout_height="wrap_content"
6
        android:layout_toLeftOf="@+id/sidespinner_view_value"/> 
7
   <TextView
8
        android:id="@+id/sidespinner_view_current_value"
9
        android:layout_width="wrap_content"
10
        android:layout_height="wrap_content"
11
        android:textSize="24sp" />
12
   <Button
13
        android:id="@+id/sidespinner_view_next"
14
        android:layout_width="wrap_content"
15
        android:layout_height="wrap_content" />
16
</merge>

Selanjutnya, kita perlu membuat kelas SideSpinner yang mengembangkan layout ini dan menetapkan panah sebagai gambar latar belakang untuk tombol. Pada titik ini, view gabungan tidak melakukan apa-apa karena belum ada yang ditampilkan.

1
public class SideSpinner extends LinearLayout {
2
3
   private Button mPreviousButton;
4
   private Button mNextButton;
5
6
   public SideSpinner(Context context) {
7
      super(context);
8
      initializeViews(context);
9
   }
10
11
   public SideSpinner(Context context, AttributeSet attrs) {
12
      super(context, attrs);
13
      initializeViews(context);
14
   }
15
16
   public SideSpinner(Context context, 
17
                      AttributeSet attrs, 
18
                      int defStyle) {
19
      super(context, attrs, defStyle);
20
      initializeViews(context);
21
   }
22
23
   /**

24
    * Inflates the views in the layout.

25
    * 

26
    * @param context

27
    *           the current context for the view.

28
    */
29
   private void initializeViews(Context context) {
30
      LayoutInflater inflater = (LayoutInflater) context
31
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
32
      inflater.inflate(R.layout.sidespinner_view, this);
33
   }
34
35
   @Override
36
   protected void onFinishInflate() {
37
      super.onFinishInflate();
38
39
      // Sets the images for the previous and next buttons. Uses 

40
      // built-in images so you don't need to add images, but in 

41
      // a real application your images should be in the 

42
      // application package so they are always available.

43
      mPreviousButton = (Button) this
44
        .findViewById(R.id.sidespinner_view_previous);
45
      mPreviousButton
46
        .setBackgroundResource(android.R.drawable.ic_media_previous);
47
48
      mNextButton = (Button)this
49
                       .findViewById(R.id.sidespinner_view_next);
50
      mNextButton
51
        .setBackgroundResource(android.R.drawable.ic_media_next);
52
   }
53
}

Anda akan melihat bahwa view gabungan memperluas grup view LinearLayout. Ini berarti bahwa layout apa pun yang menggunakan view gabungan memiliki akses ke atribut layout linier. Akibatnya, layout view gabungan sedikit berbeda dari biasanya, tag root adalah tag <merge> sebagai ganti tag untuk grup view seperti <LinearLayout> atau <RelativeLayout>.

Saat Anda menambahkan view gabungan ke layout MainActivity, tag untuk view gabungan akan bertindak sebagai tag LinearLayout. Kelas view gabungan dapat berasal dari kelas mana pun yang berasal dari ViewGroup, tetapi dalam hal ini layout linier adalah yang paling tepat karena view ditata secara horizontal.

4. Menambahkan View Gabungan ke Layout

Pada titik ini, proyek dikompilasi tetapi tidak ada yang terlihat karena view gabungan tidak dalam layout MainActivity. View side spinner harus ditambahkan ke layout activity seperti view lainnya. Nama tag adalah nama lengkap dari kelas SideSpinner, termasuk namespace.

Untuk menambahkan side spinner ke MainActivity, tambahkan yang berikut ini ke layout relatif di file /res/layout/activity_main.xml.

1
<com.cindypotvin.sidespinnerexample.SideSpinner
2
   android:id="@+id/sidespinner_fruits"
3
   android:layout_width="match_parent"
4
   android:layout_height="wrap_content"
5
   android:orientation="horizontal"
6
   android:gravity="center"/>

 Atribut yang tersedia dalam tag <SideSpinner> adalah atribut dari layout linier sejak kelas SideSpinner yang kita buat memperluas kelas LinearLayout. Jika Anda meluncurkan proyeknya, side spinner harus terlihat, tetapi tidak mengandung nilai apa pun.

5. Menambahkan Metode ke View Gabungan

Masih ada beberapa hal yang hilang jika kita ingin benar-benar menggunakan side spinner. Kita harus dapat menambahkan nilai baru ke spinner, memilih nilai, dan mendapatkan nilai yang dipilih.

Cara termudah untuk menambahkan perilaku baru ke view gabungan adalah menambahkan metode public baru ke kelas SideSpinner. Metode ini dapat digunakan oleh Activity apa pun yang memiliki referensi ke view.

1
private CharSequence[] mSpinnerValues = null;
2
private int mSelectedIndex = -1;
3
4
/**

5
 * Sets the list of value in the spinner, selecting the first value 

6
 * by default.

7
 * 

8
 * @param values

9
 *           the values to set in the spinner.

10
 */
11
public void setValues(CharSequence[] values) {
12
   mSpinnerValues = values;
13
14
   // Select the first item of the string array by default since 

15
   // the list of value has changed.

16
   setSelectedIndex(0);
17
}
18
19
/**

20
 * Sets the selected index of the spinner.

21
 * 

22
 * @param index

23
 *           the index of the value to select.

24
 */
25
public void setSelectedIndex(int index) {
26
   // If no values are set for the spinner, do nothing.

27
   if (mSpinnerValues == null || mSpinnerValues.length == 0)
28
      return;
29
30
   // If the index value is invalid, do nothing.

31
   if (index < 0 || index >= mSpinnerValues.length)
32
      return;
33
34
   // Set the current index and display the value.

35
   mSelectedIndex = index;
36
   TextView currentValue;
37
   currentValue = (TextView)this
38
                  .findViewById(R.id.sidespinner_view_current_value);
39
   currentValue.setText(mSpinnerValues[index]);
40
41
   // If the first value is shown, hide the previous button.

42
   if (mSelectedIndex == 0)
43
      mPreviousButton.setVisibility(INVISIBLE);
44
   else
45
      mPreviousButton.setVisibility(VISIBLE);
46
47
   // If the last value is shown, hide the next button.

48
   if (mSelectedIndex == mSpinnerValues.length - 1)
49
      mNextButton.setVisibility(INVISIBLE);
50
   else
51
      mNextButton.setVisibility(VISIBLE);
52
}
53
54
/**

55
 * Gets the selected value of the spinner, or null if no valid 

56
 * selected index is set yet.

57
 * 

58
 * @return the selected value of the spinner.

59
 */
60
public CharSequence getSelectedValue() {
61
   // If no values are set for the spinner, return an empty string.

62
   if (mSpinnerValues == null || mSpinnerValues.length == 0)
63
      return "";
64
65
   // If the current index is invalid, return an empty string.

66
   if (mSelectedIndex < 0 || mSelectedIndex >= mSpinnerValues.length)
67
      return "";
68
69
   return mSpinnerValues[mSelectedIndex];
70
}
71
72
/**

73
 * Gets the selected index of the spinner.

74
 * 

75
 * @return the selected index of the spinner.

76
 */
77
public int getSelectedIndex() {
78
   return mSelectedIndex;
79
}

Metode onFinishInflate dari view gabungan dipanggil ketika semua view dalam layout meningkat dan siap digunakan. Ini adalah tempat untuk menambahkan kode Anda jika Anda perlu mengubah view dalam view gabungan.

Dengan metode yang baru saja Anda tambahkan ke kelas SideSpinner, perilaku untuk tombol yang memilih nilai sebelumnya dan selanjutnya sekarang dapat ditambahkan. Ganti kode yang ada dalam metode onFinishInflate dengan yang berikut:

1
@Override
2
protected void onFinishInflate() {
3
4
   // When the controls in the layout are doing being inflated, set 

5
   // the callbacks for the side arrows.

6
   super.onFinishInflate();
7
8
   // When the previous button is pressed, select the previous value 

9
   // in the list.

10
   mPreviousButton = (Button) this
11
      .findViewById(R.id.sidespinner_view_previous);
12
   mPreviousButton
13
      .setBackgroundResource(android.R.drawable.ic_media_previous);
14
15
   mPreviousButton.setOnClickListener(new OnClickListener() {
16
      public void onClick(View view) {
17
         if (mSelectedIndex > 0) {
18
            int newSelectedIndex = mSelectedIndex - 1;
19
            setSelectedIndex(newSelectedIndex);
20
         }
21
      }
22
   });
23
24
   // When the next button is pressed, select the next item in the 

25
   // list.

26
   mNextButton = (Button)this
27
                    .findViewById(R.id.sidespinner_view_next);
28
   mNextButton
29
      .setBackgroundResource(android.R.drawable.ic_media_next);
30
   mNextButton.setOnClickListener(new OnClickListener() {
31
      public void onClick(View view) {
32
         if (mSpinnerValues != null
33
               && mSelectedIndex < mSpinnerValues.length - 1) {
34
            int newSelectedIndex = mSelectedIndex + 1;
35
            setSelectedIndex(newSelectedIndex);
36
         }
37
      }
38
   });
39
40
   // Select the first value by default.

41
   setSelectedIndex(0);
42
}

Dengan metode setValues dan setSelectedIndex yang baru dibuat, kita sekarang dapat menginisialisasi side spinner dari kode kita. Seperti halnya view lain, Anda perlu menemukan view side spinner dalam layout dengan metode findViewById. Kita kemudian dapat memanggil metode public apa pun pada view dari objek yang dikembalikan, termasuk yang baru saja kita buat.

Potongan kode berikut menunjukkan cara memperbarui metode onCreate dari kelas MainActivity untuk menampilkan daftar nilai di side spinner, menggunakan metode setValues. Kita juga dapat memilih nilai kedua dalam daftar secara default dengan menerapkan metode setSelectedIndex.

1
public class MainActivity extends Activity {
2
3
   @Override
4
   protected void onCreate(Bundle savedInstanceState) {
5
      super.onCreate(savedInstanceState);
6
      setContentView(R.layout.activity_main);
7
8
      // Initializes the side spinner from code.

9
      SideSpinner fruitsSpinner;
10
      fruitsSpinner = (SideSpinner)this
11
                         .findViewById(R.id.sidespinner_fruits);
12
13
      CharSequence fruitList[] = { "Apple", 
14
                                   "Orange", 
15
                                   "Pear", 
16
                                   "Grapes" };
17
      fruitsSpinner.setValues(fruitList);
18
      fruitsSpinner.setSelectedIndex(1);
19
   }
20
}

Jika Anda meluncurkan aplikasi, side spinner akan berfungsi seperti yang diharapkan. Daftar nilai ditampilkan dan nilai Orange dipilih secara default.

6. Menambahkan Atribut Layout ke View Gabungan

View yang tersedia di SDK Android dapat dimodifikasi melalui kode, tetapi beberapa atribut juga dapat diatur secara langsung di layout yang sesuai. Mari tambahkan sebuah atribut ke side spinner yang menetapkan nilai yang dibutuhkan oleh side spinner untuk ditampilkan.

Untuk membuat atribut khusus untuk view gabungan, pertama-tama kita perlu mendefinisikan atribut di file /res/values/attr.xml. Setiap atribut view gabungan harus dikelompokkan dalam sebuah styleable dengan tag <declare-styleable>. Untuk side spinner, nama kelas digunakan seperti yang ditunjukkan di bawah ini.

1
<resources>
2
  <declare-styleable name="SideSpinner">
3
    <attr name="values" format="reference" />
4
  </declare-styleable>
5
</resources>

Dalam tag <attr>, atribut name berisi identifier yang digunakan untuk merujuk ke atribut baru dalam layout dan atribut format berisi jenis atribut baru.

Untuk daftar nilai, jenis reference digunakan karena atribut akan merujuk ke daftar string yang didefinisikan sebagai sumber daya. Jenis nilai yang biasanya digunakan dalam layout dapat digunakan untuk atribut khusus Anda, termasuk booleancolordimensionenumintegerfloat dan string.

Di sini adalah bagaimana mendefinisikan sumber daya untuk daftar string yang atribut values dari side spinner akan merujuk. Ini harus ditambahkan ke file /res/values/strings.xml seperti yang ditunjukkan di bawah ini.

1
<resources>
2
    <string-array name="vegetable_array">
3
        <item>Cucumber</item>
4
        <item>Potato</item>
5
        <item>Tomato</item>
6
        <item>Onion</item>
7
        <item>Squash</item>
8
    </string-array>  
9
</resources>

Untuk menguji atribut values yang baru, buat view side spinner dalam layout MainActivity di bawah side spinner yang ada. Atribut harus diawali dengan namespace yang ditambahkan ke RelativeLayout, seperti xmlns:sidespinner="http://schemas.android.com/apk/res-auto". Ini adalah layout akhir di /res/layout/activity_main.xml.

1
<RelativeLayout 
2
    xmlns:android="http://schemas.android.com/apk/res/android"
3
    xmlns:tools="http://schemas.android.com/tools"
4
    xmlns:sidespinner="http://schemas.android.com/apk/res-auto"
5
    android:layout_width="match_parent"
6
    android:layout_height="match_parent"
7
    tools:context=".MainActivity">
8
    <com.cindypotvin.sidespinnerexample.SideSpinner
9
      android:id="@+id/sidespinner_fruits"
10
      android:layout_width="match_parent"
11
      android:layout_height="wrap_content"
12
      android:orientation="horizontal"
13
      android:gravity="center"/>
14
    
15
     <com.cindypotvin.sidespinnerexample.SideSpinner
16
      android:id="@+id/sidespinner_vegetables"
17
      android:layout_width="match_parent"
18
      android:layout_height="wrap_content"
19
      android:orientation="horizontal"
20
      android:gravity="center"
21
      android:layout_below="@id/sidespinner_fruits" 
22
      sidespinner:values="@array/vegetable_array" />
23
</RelativeLayout>

Akhirnya, kelas SideSpinner perlu dimodifikasi untuk membaca atribut values. Nilai setiap atribut view tersedia di objek AttributeSet yang dilewatkan sebagai parameter constructor dari view.

Untuk mendapatkan nilai dari atribut values kustom Anda, pertama kita memanggil metode obtainStyledAttributes dari objek AttributeSet dengan nama styleable yang berisi atributnya. Ini mengembalikan daftar atribut untuk styleable itu sebagai objek TypedArray.

Kita kemudian memanggil metode getter dari objek TypedArray yang memiliki tipe yang tepat untuk atribut yang Anda inginkan, mengirimkan identifier atribut sebagai sebuah parameter. Blok kode berikut menunjukkan bagaimana memodifikasi constructor dari side spinner untuk mendapatkan daftar nilai dan menetapkannya di side spinner.

1
public SideSpinner(Context context) {
2
   super(context);
3
4
   initializeViews(context);
5
}
6
7
public SideSpinner(Context context, AttributeSet attrs) {
8
   super(context, attrs);
9
10
   TypedArray typedArray;
11
   typedArray = context
12
             .obtainStyledAttributes(attrs, R.styleable.SideSpinner);
13
   mSpinnerValues = typedArray
14
                       .getTextArray(R.styleable.SideSpinner_values);
15
   typedArray.recycle();
16
17
   initializeViews(context);
18
}
19
20
public SideSpinner(Context context, 
21
                   AttributeSet attrs,
22
                   int defStyle) {
23
   super(context, attrs, defStyle);
24
25
   TypedArray typedArray;
26
   typedArray = context
27
             .obtainStyledAttributes(attrs, R.styleable.SideSpinner);
28
   mSpinnerValues = typedArray
29
                       .getTextArray(R.styleable.SideSpinner_values);
30
   typedArray.recycle();
31
32
   initializeViews(context);
33
}

Jika Anda meluncurkan aplikasi, Anda akan melihat dua side spinner yang bekerja secara independen dari satu sama lain.

7. Menyimpan dan Memulihkan Keadaan

Langkah terakhir yang perlu kita selesaikan adalah menyimpan dan memulihkan keadaan dari view gabungan. Ketika suatu activity dihancurkan dan dibuat ulang, misalnya, ketika perangkat diputar, nilai-nilai view asli dengan pengenal unik secara otomatis disimpan dan dipulihkan. Ini saat ini tidak berlaku untuk side spinner.

Keadaan view tidak disimpan. Pengidentifikasi view di kelas SideSpinner tidak unik karena dapat digunakan kembali berkali-kali. Ini berarti bahwa kita bertanggung jawab untuk menyimpan dan memulihkan nilai-nilai view dalam view gabungan. Kita melakukan ini dengan menerapkan metode onSaveInstanceState, onRestoreInstanceState, dan dispatchSaveInstanceState. Blok kode berikut menunjukkan bagaimana melakukan ini untuk side spinner.

1
/**

2
 * Identifier for the state to save the selected index of 

3
 * the side spinner.

4
 */
5
private static String STATE_SELECTED_INDEX = "SelectedIndex";
6
7
/**

8
 * Identifier for the state of the super class.

9
 */
10
private static String STATE_SUPER_CLASS = "SuperClass";
11
12
@Override
13
protected Parcelable onSaveInstanceState() { 
14
   Bundle bundle = new Bundle();
15
16
    bundle.putParcelable(STATE_SUPER_CLASS,
17
                         super.onSaveInstanceState());
18
    bundle.putInt(STATE_SELECTED_INDEX, mSelectedIndex);
19
20
    return bundle;
21
}
22
23
@Override
24
protected void onRestoreInstanceState(Parcelable state) {
25
    if (state instanceof Bundle) {
26
        Bundle bundle = (Bundle)state;
27
28
        super.onRestoreInstanceState(bundle
29
                                 .getParcelable(STATE_SUPER_CLASS));
30
        setSelectedIndex(bundle.getInt(STATE_SELECTED_INDEX));
31
    } 
32
    else
33
       super.onRestoreInstanceState(state);   
34
}
35
36
@Override
37
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
38
    // Makes sure that the state of the child views in the side 

39
    // spinner are not saved since we handle the state in the

40
    // onSaveInstanceState.

41
    super.dispatchFreezeSelfOnly(container);
42
}
43
44
@Override
45
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
46
    // Makes sure that the state of the child views in the side 

47
    // spinner are not restored since we handle the state in the

48
    // onSaveInstanceState.

49
    super.dispatchThawSelfOnly(container);
50
}

Kesimpulan

Side spinner sekarang selesai. Kedua side spinner bekerja seperti yang diharapkan dan nilai-nilai mereka dipulihkan jika aktivitas dihancurkan dan dibuat ulang. Anda sekarang dapat menerapkan apa yang telah Anda pelajari untuk menggunakan kembali sekumpulan view dalam aplikasi Android dengan menggunakan view gabungan.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.