Tugas 1: Mengunduh Kode Starter
1.1 Buka dan Jalankan Proyek Material Me
- Unduh dan buka zip file MaterialMe-Starter.
- Buka aplikasi di Android Studio.
- Bangun dan jalankan aplikasi.
1.2 Jelajahi Aplikasi
-
Sebelum membuat modifikasi pada aplikasi, jelajahi strukturnya saat ini. Strukturnya berisi elemen berikut:
-
Sport.java
Kelas ini mewakili model data untuk setiap baris data di RecyclerView. Sekarang, ini berisi sebuah bidang untuk judul olahraga dan sebuah bidang untuk beberapa informasi tentang olahraga.
-
/* * Copyright (C) 2016 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.materialme; /** * Data model for each row of the RecyclerView. */ class Sport { //Member variables representing the title and information about the sport private String title; private String info; /** * Constructor for the Sport data model * @param title The name if the sport. * @param info Information about the sport. */ Sport(String title, String info) { this.title = title; this.info = info; } /** * Gets the title of the sport * @return The title of the sport. */ String getTitle() { return title; } /** * Gets the info about the sport * @return The info about the sport. */ String getInfo() { return info; } }
-
SportsAdapter.java
Ini adalah adaptor untuk RecyclerView. Ini menggunakan ArrayList objek olahraga sebagai datanya dan mengisi setiap baris dengan data ini.
-
/* * Copyright (C) 2016 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.materialme; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.util.ArrayList; /*** * The adapter class for the RecyclerView, contains the sports data */ class SportsAdapter extends RecyclerView.Adapter<SportsAdapter.ViewHolder> { //Member variables private ArrayList<Sport> mSportsData; private Context mContext; /** * Constructor that passes in the sports data and the context * @param sportsData ArrayList containing the sports data * @param context Context of the application */ SportsAdapter(Context context, ArrayList<Sport> sportsData) { this.mSportsData = sportsData; this.mContext = context; } /** * Required method for creating the viewholder objects. * @param parent The ViewGroup into which the new View will be added after it is bound to an adapter position. * @param viewType The view type of the new View. * @return The newly create ViewHolder. */ @Override public SportsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.list_item, parent, false)); } /** * Required method that binds the data to the viewholder. * @param holder The viewholder into which the data should be put. * @param position The adapter position. */ @Override public void onBindViewHolder(SportsAdapter.ViewHolder holder, int position) { //Get current sport Sport currentSport = mSportsData.get(position); //Populate the textviews with data holder.bindTo(currentSport); } /** * Required method for determining the size of the data set. * @return Size of the data set. */ @Override public int getItemCount() { return mSportsData.size(); } /** * ViewHolder class that represents each row of data in the RecyclerView */ class ViewHolder extends RecyclerView.ViewHolder { //Member Variables for the TextViews private TextView mTitleText; private TextView mInfoText; /** * Constructor for the ViewHolder, used in onCreateViewHolder(). * @param itemView The rootview of the list_item.xml layout file */ ViewHolder(View itemView) { super(itemView); //Initialize the views mTitleText = (TextView)itemView.findViewById(R.id.title); mInfoText = (TextView)itemView.findViewById(R.id.subTitle); } void bindTo(Sport currentSport){ //Populate the textviews with data mTitleText.setText(currentSport.getTitle()); mInfoText.setText(currentSport.getInfo()); } } }
-
MainActivity.java
MainActivity melakukan inisialisasi RecyclerView dan adaptor, dan membuat data dari file sumber daya.
-
/* * Copyright (C) 2016 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.materialme; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import java.util.ArrayList; /*** * Main Activity for the Material Me app, a mock sports news application with poor design choices */ public class MainActivity extends AppCompatActivity { //Member variables private RecyclerView mRecyclerView; private ArrayList<Sport> mSportsData; private SportsAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Initialize the RecyclerView mRecyclerView = (RecyclerView)findViewById(R.id.recyclerView); //Set the Layout Manager mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); //Initialize the ArrayLIst that will contain the data mSportsData = new ArrayList<>(); //Initialize the adapter and set it ot the RecyclerView mAdapter = new SportsAdapter(this, mSportsData); mRecyclerView.setAdapter(mAdapter); //Get the data initializeData(); } /** * Method for initializing the sports data from resources. */ private void initializeData() { //Get the resources from the XML file String[] sportsList = getResources().getStringArray(R.array.sports_titles); String[] sportsInfo = getResources().getStringArray(R.array.sports_info); //Clear the existing data (to avoid duplication) mSportsData.clear(); //Create the ArrayList of Sports objects with the titles and information about each sport for(int i=0;i<sportsList.length;i++){ mSportsData.add(new Sport(sportsList[i],sportsInfo[i])); } //Notify the adapter of the change mAdapter.notifyDataSetChanged(); } }
-
strings.xml
File sumber daya ini berisi semua data untuk aplikasi, termasuk judul dan informasi untuk setiap olahraga.
-
<resources> <string name="app_name">Material Me!</string> <string name="title_placeholder">Title</string> <string name="news_placeholder">News</string> <string name="sports_info_placeholder">Here is some news</string> <string-array name="sports_titles"> <item>Baseball</item> <item>Badminton</item> <item>Basketball</item> <item>Bowling</item> <item>Cycling</item> <item>Golf</item> <item>Running</item> <item>Soccer</item> <item>Swimming</item> <item>Table Tennis</item> <item>Tennis</item> </string-array> <string-array name="sports_info"> <item>Here is some Baseball news!</item> <item>Here is some Badminton news!</item> <item>Here is some Basketball news!</item> <item>Here is some Bowling news!</item> <item>Here is some Cycling news!</item> <item>Here is some Golf news!</item> <item>Here is some Running news!</item> <item>Here is some Soccer news!</item> <item>Here is some Swimming news!</item> <item>Here is some Table Tennis news!</item> <item>Here is some Tennis news!</item> </string-array> </resources>
-
list_item.xml
File layout ini mendefinisikan setiap baris RecyclerView. Ini terdiri dari tiga TextView, satu untuk setiap bagian data (judul dan info untuk setiap olahraga) dan satu digunakan sebagai label.
-
<?xml version="1.0" encoding="utf-8"?> <!-- Copyright 2016 Google Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/title" android:text="@string/title_placeholder" android:padding="8dp" style="@style/TextAppearance.AppCompat.Headline"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/newsTitle" android:text="@string/news_placeholder" android:padding="8dp" style="@style/TextAppearance.AppCompat.Subhead" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/subTitle" android:text="@string/sports_info_placeholder" android:padding="8dp" style="@style/TextAppearance.AppCompat.Subhead" /> </LinearLayout>
Tugas 2: Menambahkan CardView dan Gambar
2.1 Tambahkan CardView
Di file build.gradle tingkat aplikasi Anda, tambahkan baris berikut ke blok dependensi: Catatan: Versi pustaka dukungan mungkin telah berubah sejak penulisan praktik ini. Perbarui ke versi paling baru dan sinkronkan file gradle Anda.
Di file list_item.xml, kurung LinearLayout root dengan CardView dengan atribut berikut:
Atribut | Nilai |
android:layout_width | “match_parent” |
android:layout_height | “wrap_content” |
android:layout_margin | “8dp” |
xmlns:android="http://schemas.android.com/apk/res/android"
) dari LinearLayout ke CardView yang sekarang menjadi View tingkat tinggi file layout Anda.- Unduh file zip gambar spanduk.
- Salin file ini ke direktori res > drawable di aplikasi Anda.
Definisikan larik yang berisi semua jalur ke drawable sebagai item di file string.xml Anda. Pastikan larik dalam urutan yang sama dengan larik judul olahraga:
<array name="sports_images">
<item>@drawable/img_baseball</item>
<item>@drawable/img_badminton</item>
<item>@drawable/img_basketball</item>
<item>@drawable/img_bowling</item>
<item>@drawable/img_cycling</item>
<item>@drawable/img_golf</item>
<item>@drawable/img_running</item>
<item>@drawable/img_soccer</item>
<item>@drawable/img_swimming</item>
<item>@drawable/img_tabletennis</item>
<item>@drawable/img_tennis</item>
</array>
Modifikasi objek Sport
Objek Sport.java perlu menyertakan sumber daya yang dapat digambar yang berkaitan dengan olahraga. Untuk mencapai ini:
- Tambahkan variabel anggota integer ke objek Sport yang akan berisi sumber daya yang dapat digambar:
private final int imageResource;
- Modifikasi konstruktor sehingga akan mengambil sebuah integer sebagai parameter dan menetapkannya ke variabel anggota:
public Sport(String title, String info, int imageResource) { this.title = title; this.info = info; this.imageResource = imageResource; }
- Buat getter untuk integer sumber daya:
public int getImageResource() { return imageResource; }
Perbaiki metode initializeData()
- Dalam metode
initializeData()
, dapatkan TypedArray id sumber daya dengan memanggilgetResources().obtainTypedArray()
, dan meneruskan nama larik sumber daya yang dapat digambar, yang Anda definisikan di file strings.xml:TypedArray sportsImageResources = getResources().obtainTypedArray(R.array.sports_images);
Anda bisa mengakses elemen pada indeks i di TypedArray dengan menggunakan metode “get” yang sesuai, bergantung pada tipe sumber daya di larik. Dalam kasus spesifik ini, ini berisi ID sumber daya, sehingga Anda bisa menggunakan metode
getResourceId()
.
- Perbaiki kode di loop yang membuat objek Sport, dengan menambahkan ID sumber daya yang dapat digambar yang sesuai sebagai parameter ketiga dengan memanggil
getResourceId()
di TypedArray:for(int i=0;i<sportsList.length;i++){ mSportsData.add(new Sport(sportsList[i],sportsInfo[i], sportsImageResources.getResourceId(i,0))); }
- Bersihkan data di TypedArray setelah Anda membuat ArrayList data Sport:
sportsImageResources.recycle();
-
2.5 Tambahkan ImageView ke item daftar
- Ubah LinearLayout di dalam file list_item.xml menjadi RelativeLayout, dan hapus atribut orientasi.
- Tambahkan ImageView dengan atribut berikut:
Atribut Nilai android:layout_width “match_parent” android:layout_height “wrap_content” android:id “@+id/sportsImage” android:adjustViewBounds “true” Atribut
adjustViewBounds
membuat ImageView menyesuaikan batasnya untuk mempertahankan rasio aspek gambar.
-
Tambahkan atribut berikut ke TextView yang ada:
TextView id: title Atribut Nilai android:layout_alignBottom “@id/sportsImage” android:theme “@style/ThemeOverlay.AppCompat.Dark” TextView id: newsTitle Atribut Nilai android:layout_below “@id/sportsImage” android:textColor “?android:textColorSecondary” TextView id: subTitle android:layout_below “@id/newsTitle” Catatan: Tanda tanya di atribut textColor di atas (“?android:textColorSecondary”) artinya adalah framework akan menerapkan nilai dari tema yang saat ini diterapkan. Dalam hal ini, atribut ini diwarisi dari tema “Theme.AppCompat.Light.DarkActionBar” yang mende
2.6 Muat gambar menggunakan Glide
- Tambahkan dependensi berikut untuk Glide, di file build.gradle tingkat aplikasi Anda:
-
compile 'com.github.bumptech.glide:glide:3.5.2'
- Tambahkan variabel di kelas SportsAdapter, kelas ViewHolder untuk ImageView, dan lakukan inisialisasi di konstruktor ViewHolder:
mSportsImage = (ImageView) itemView.findViewById(R.id.sportsImage);
- Tambahkan baris kode berikut ke
onBindViewHolder()
untuk mendapatkan sumber daya gambar dari objek Sport dan muat ke dalam ImageView menggunakan Glide:Glide.with(mContext).load(currentSport.getImageResource()).into(holder.mSportsImage);
Begitulah cara memuat gambar dengan Glide. Glide juga memiliki beberapa fitur tambahan yang memungkinkan Anda mengubah ukuran, mentransformasi, dan memuat gambar dengan berbagai cara. Kunjungi laman GitHub Glide untuk mengetahui selengkapnya.
Tugas 3: Membuat CardView Anda bisa digesek, dipindahkan, dan diklik
3.1 Implementasikan gesek untuk menutup
Lakukan yang berikut:
-
Buat objek ItemTouchHelper baru, di metode
onCreate()
MainActivity.java. Untuk argumennya, buat instance baru ItemTouchHelper.SimpleCallback dan tekan Enter untuk membuat Android Studio mengisi metode yang diperlukan:onMove()
danonSwiped()
.Catatan: Jika metode yang diperlukan tidak otomatis ditambahkan, klik bola lampu merah dan pilih Implement methods. -
Konstruktor SimpleCallback akan diberi garis bawah merah karena Anda belum menyediakan parameter yang diperlukan: arah yang Anda rencanakan untuk mendukung pemindahan dan penggesekan item daftar.
Karena kita hanya mengimplementasikan gesek untuk menutup sekarang, Anda harus meneruskan
0
untuk arah pemindahan yang didukung danItemTouchHelper.LEFT | ItemTouchHelper.RIGHT
untuk arah penggesekan yang didukung:ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper .SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {}
- Sekarang Anda harus mengimplementasikan perilaku yang diinginkan di
onSwiped()
. Dalam hal ini, menggesek kartu ke kiri atau ke kanan akan menghapusnya dari daftar. Panggiliremove()
di rangkaian data, dengan meneruskan indeks yang sesuai dengan mendapatkan posisi dari ViewHolder:mSportsData.remove(viewHolder.getAdapterPosition());
- Agar RecyclerView dapat menggerakkan penghapusan dengan benar, Anda juga harus memanggil
notifyItemRemoved()
, lagi dengan meneruskan indeks yang sesuai dengan mendapatkan posisi dari ViewHolder:mAdapter.notifyItemRemoved(viewHolder.getAdapterPosition());
- Setelah membuat objek ItemTouchHelper baru di metode
onCreate()
MainActivity, pangilattachToRecyclerView()
di instance ItemTouchHelper untuk menambahkannya ke RecyclerView Anda:helper.attachToRecyclerView(mRecyclerView);
Implementasikan tampilan detail
- Buat aktivitas baru dengan masuk ke File > New > Activity > Empty Activity.
- Beri nama DetailActivity, dan terima semua default.
- Di file layout yang baru dibuat, buang padding dari RelativeLayout rootview.
- Salin semua dari tampilan TextView dan ImageView dari file list_item.xml ke file activity_detail.xml.
- Tambahkan kata “Detail” ke setiap referensi ke sebuah id, untuk membedakannya dengan id list_item. Misalnya, ubah id ImageView dari sportsImage ke sportsImageDetail, serta semua referensi ke id ini untuk penepatan relatif, seperti
layout_below.
- Untuk textview subTitleDetal, buang semua string teks placeholder dan tempelkan paragraf teks generik untuk menggantikan semua teks detail (Misalnya, beberapa paragraf Lorem Ipsum).
- Ubah padding TextView menjadi 16dp.
-
Bungkus keseluruhan activity_detail.xml di ScrollView dan ubah atribut layout_height RelativeLayout ke “wrap_content”.
Catatan: Atribut untuk ScrollView mungkin berwarna merah terlebih dulu. Ini karena Anda harus menambahkan atribut yang mendefinisikan namespace Android. Ini adalah atribut yang muncul di semua file layout Anda secara default:xmlns:android="http://schemas.android.com/apk/res/android"
.
Cukup pindahkan deklarasi ini ke tampilan tingkat atas dan warna merah pun akan hilang. -
Dalam kelas SportsAdapter, buat kelas dalam ViewHolder agar mengimplementasikan View.OnClickListener dan dan implementasikan metode yang diperlukan (
onClick()
). - Setel OnClickListener ke itemview di konstruktor:
itemView.setOnClickListener(this);
- Dalam metode
onClick()
, dapatkan objek Sport untuk item yang diklik menggunakangetAdapterPosition()
.Sport currentSport = mSportsData.get(getAdapterPosition());
- Buat sebuah Intent yang meluncurkan aktivitas Detail, dan letakkan judul dan sumber daya gambar sebagai ekstra di Intent:
Intent detailIntent = new Intent(mContext, DetailActivity.class); detailIntent.putExtra("title", currentSport.getTitle()); detailIntent.putExtra("image_resource", currentSport.getImageResource());
- Panggil
startActivity()
di variabel mContext, dengan meneruskan Intent baru. - Dalam DetailActivity.java, lakukan inisialisasi ImageView dan TextView judul di
onCreate()
:TextView sportsTitle = (TextView)findViewById(R.id.titleDetail); ImageView sportsImage = (ImageView)findViewById(R.id.sportsImageDetail);
- Dapatkan judul dari Intent yang masuk dan setel ke TextView:
sportsTitle.setText(getIntent().getStringExtra("title"));
- Gunakan Glide untuk memuat gambar ke dalam ImageView:
Glide.with(this).load(getIntent().getIntExtra("image_resource",0)) .into(sportsImage);
- Jalankan aplikasi. Mengetuk item daftar sekarang meluncurkan aktivitas detail.
Tugas 4: Tambahkan FAB dan pilih Palet Warna Material
4.1 Tambahkan FAB
Tombol Aksi Mengambang adalah bagian dari Pustaka Dukungan Desain.
- Tambahkan baris kode berikut ke file build.gradle tingkat aplikasi untuk menambahkan dependensi pustaka dukungan desain:
compile 'com.android.support:design:24.2.1'
- Gunakan studio aset vektor untuk mengunduh ikon untuk digunakan di FAB. Tombol akan menyetel ulang konten di RecyclerView sehingga ikon ini akan melakukan: . Mengubah nama ke ic_reset.
- Di activity_main.xml, tambahkan tampilkan Tombol Aksi Mengambang dengan parameter berikut:
Atribut Nilai android:layout_width “wrap_content” android:layout_height “wrap_content” android:layout_alignParentBottom “true” android:layout_alignParentRight “true android:layout_margin “16dp” android:src “@drawable/ic_reset” android:onClick resetSports - Definisikan metode
resetSports()
di MainActivity.java agar cukup memanggil initializeData() untuk menyetel ulang data. -
Jalankan aplikasi. Anda sekarang bisa menyetel ulang data dengan menekan FAB.
Catatan: Karena aktivitas dihapus dan dibuat ulang saat konfigurasi berubah, memutar perangkat akan menyetel ulang data pada implementasi ini. Agar perubahan menjadi persisten (seperti kasus mengubah urutan dan membuang data), Anda harus mengimplementasikanonSaveInstanceState()
atau menuliskan perubahan ke sumber yang persisten (seperti database atau SharedPreferences).