یکی از ویجتهای کاربردی در اندروید ListView است که به کمک آن میتوان لیستی ازآیتمها را نمایش داد. ListView میتواند محدودیتی برای تعداد آیتم ها نداشته باشد و scroll شود.
Static lists
در این حالت محتوای لیست ثابت است و از قبل مشخص شده. در این حالت یکی از روشها درست کردن لیستی در strings.xml است. میتوانید این لیست را در resource ها درست کنید و به پارامتر entries در ListView بدهید.
Dynamic lists
محتوای لیست در طی اجرای برنامه ساخته میشود. در این صورت محتوا باید از طریق کد جاوا به لیست داده شود. در ListView امکان شخصی سازی وجود دارد و آیتم ها از ساده ترین حالت یعنی یک text تا یک آیتم پیچیده (ترکیبی از تصویر، متن، لینک و…) قابل پیاده سازی هستند. داده ها از منابعی مانند آرایه ها و دیتابیس و یا از اینترنت به ListView منتقل و نمایش داده می شوند.
اطلاعات ما میتواند یک لیست متنی مانند لیست زیر باشد:
List adapters
زمانی از Adapter ها استفاده میکنیم که میخواهیم اطلاعاتی را بین منبع ان و واسط گرافیکی منتقل کنیم و ان را نمایش دهیم. Adapter این وظیفه را دارد که این اطلاعات را منتقل کند. با کمک آن اطلاعات خود را به لیست انتقال می دهیم و ان را نمایش می دهیم. در مثال زیر یک نمونه استفاده از ArrayAdapter را مشاهده میکنید:
ابتدا فایل xml درست کرده و ویجت ListView را اضافه میکنیم.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="ir.android_studio.simplelistview.MainActivity"> <ListView android:id="@+id/list_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentStart="true" android:layout_alignParentTop="true" /> </RelativeLayout>
سپس ویجت ListView را در اکتیویتی تعریف میکنیم:
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.ListView; public class MainActivity extends AppCompatActivity { ListView mListView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView = findViewById(R.id.list_view); } }
در ادامه یک آرایه تعریف می کنم و سپس به واسطه Adapter مقادیر آرایه را به ListView انتقال می دهم:
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.ArrayAdapter; import android.widget.ListView; public class MainActivity extends AppCompatActivity { ListView mListView; String[] mobileBrands; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView = findViewById(R.id.list_view); mobileBrands = new String[] {"LG", "Samsung", "Apple", "Sony", "Huawei","HTC", "Motorola"}; ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mobileBrands); mListView.setAdapter(mAdapter); } }
فایل simple_list_item_1.xml فقط یک TextView درون این فایل قرار داده شده که در ArrayAdapter به عنوان دومین پارامتر ورودی معرفی می کنیم، Adapter تک تک داده ها را در این layout تکرار کرده و به ListView می فرستند که نتیجه اش همان چیزی می شود که با اجرای پروژه می بینیم. یعنی یک لیست از داده ها.
Event listener
وقتی لیستی از دادهها را میبینم احتمال این وجود دارد که بخواهیم روی آن کلیک کنیم. روی آیتمهای لیست هم حالتهای مختلفی از رویدادها تعریف شده است.
- setOnItemClickListener وقتی روی آیتمی کلیک میشود
- setOnItemLongClickListener وقتی روی آیتمی کلیک و نگه داشته میشود
- setOnItemSelectedListener وقتی آیتمی از لیست انتخاب میشود
- حالتهای دیگر که امکانپذیر است شامل: onDrag، onFocusChanged، onHover، onKey، onScroll، onTouch
مثال پیادهسازی:
ListView list = (ListView) findViewById(R.id.id); list.setOnItemClickListener( new AdapterView.OnItemClickListener() @Override public void onItemClick(AdapterView<?> list, View row, int index, long rowID){ // code to run when user clicks that item ... } } );
آموزش ایجاد لیست ویو ListView سفارشی در اندروید
در مثال بالا لیستی را درست کردیم که آیتمهایش یک لیست از string بود. اگر بخواهیم لیستی داشته باشیم که آیتمهایش پیچیدهتر باشند (ترکیب عکس و متن و …) در این صورت باید فایل xml آیتم را خودمان طراحی کنیم و به adapter بدهیم.
در این حالت دیگر نمیتوانیم از ArrayAdapter استفاده کنیم و باید Adapter مورد نیازمان را درست کنیم و متد getView را در آن پیاده سازی کنیم. در زیر یک نمونه آیتم لیست با ویجتهای دلخواه میبینید:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout_root" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <ImageView android:id="@+id/img_avatar" android:layout_width="wrap_content" android:layout_height="80dp" android:src="@drawable/avatar_1" /> <TextView android:id="@+id/txt_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Name" /> <TextView android:id="@+id/txt_time" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Time" /> <TextView android:id="@+id/txt_message" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Message" /> </LinearLayout>
هر کدام از ویجتهای بالا دیتایی برای نمایش نیاز دارند برای اینکار بهتر آن است کلاس مدل طراحی کنیم.
package ir.android_studio.customlistview; public class Item { private String imgAvatar; private String txtName; private String txtDate; private String txtMessage; public Item(String imgAvatar, String txtName, String txtDate, String txtMessage) { this.imgAvatar = imgAvatar; this.txtName = txtName; this.txtDate = txtDate; this.txtMessage = txtMessage; } public String getImgAvatar() { return imgAvatar; } public void setImgAvatar(String imgAvatar) { this.imgAvatar = imgAvatar; } public String getTxtName() { return txtName; } public void setTxtName(String txtName) { this.txtName = txtName; } public String getTxtDate() { return txtDate; } public void setTxtDate(String txtDate) { this.txtDate = txtDate; } public String getTxtMessage() { return txtMessage; } public void setTxtMessage(String txtMessage) { this.txtMessage = txtMessage; } }
در مرحلهی بعد یک CustomAdapter درست میکنیم که از یک کلاس Adapter مثلا BaseAdapter ارث ببرد و متدهای اجباری آن را پیادهسازی میکنیم.
package ir.android_studio.customlistview; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import java.util.ArrayList; public class CustomAdapter extends BaseAdapter { private Context mContext; private ArrayList<Item> mItem; public CustomAdapter(Context mContext, ArrayList<Item> mItem) { this.mContext = mContext; this.mItem = mItem; } @Override public int getCount() { return 0; } @Override public Object getItem(int i) { return null; } @Override public long getItemId(int i) { return 0; } @Override public View getView(int i, View view, ViewGroup viewGroup) { return null; } }
متد آخر یعنی متد getView متد اصلی ما محسوب میشود که تمام پردازشها در این متد انجام میشود.
همانطور که در زیر مشاهده میکنید، در قسمت اول یک if داریم که گفته تا زمانی که view برابر null باشد، دستور داخل حلقه را اجرا کن. یعنی تا زمانی که صفحه نمایش جا برای اضافه شدن آیتم جدید به ListView دارد، توسط LayoutInflater یک داده جدید به لایه list_item که حاوی یک ImageView و سه TextView هست بفرست. در ادامه نیز ویجتها را میسازیم و به آنها مقدار مورد نظر هر آیتم را اختصاص میدهیم.
@Override public View getView(int i, View view, ViewGroup viewGroup) { if (view == null) { view = LayoutInflater.from(mContext).inflate(R.layout.list_item, viewGroup, false); } Item currentItem = (Item) getItem(i); ImageView imgItemAvatar = view.findViewById(R.id.img_avatar); TextView txtItemName = view.findViewById(R.id.txt_name); TextView txtItemTime = view.findViewById(R.id.txt_time); TextView txtItemMessage = view.findViewById(R.id.txt_message); txtItemName.setText(currentItem.getTxtName()); txtItemTime.setText(currentItem.getTxtDate()); txtItemMessage.setText(currentItem.getTxtMessage()); String mUri = "@drawable/" + currentItem.getImgAvatar(); int imageSource = mContext.getResources().getIdentifier(mUri, null, mContext.getPackageName()); imgItemAvatar.setImageDrawable(ResourcesCompat.getDrawable(mContext.getResources(), imageSource, null)); return view; }
در انتهای کار سراغ Activity میرویم و بعد از اینکه ListView را ساختیم، CustomAdapter را از طریق متد setAdapter به ListView وصل میکنیم.
package ir.android_studio.customlistview; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.ListView; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { ListView mList; ArrayList<Item> arrayItem; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mList = findViewById(R.id.list_view); arrayItem = new ArrayList<>(); CustomAdapter mAdapter = new CustomAdapter(this, arrayItem); mList.setAdapter(mAdapter); } }