خانه » لایبرری های مفید و تجربیات شخصی خیلی مفید !!! » ساخت آداپتر لیست و گرید با BaseAdapter

ساخت آداپتر لیست و گرید با BaseAdapter

یکی از پر کاربرد ترین آداپتر ها برای لیست ها و گرید ها ، BaseAdapter می باشد که با extends کردن این کلاس به راحتی می توان لیست های کاستوم خود را نوشت :

در زیر نمونه ای از این کلاس ساخته شده است :

 
private class NavigationDrawerAdapter extends BaseAdapter {
private Context context;
private ArrayList<HomeList> menuArray;
private int selectedPosition;

private NavigationDrawerAdapter(Context context, ArrayList<HomeList> menuArray) {
    this.context = context;
    this.menuArray = menuArray;
}

@Override
public int getCount() {
    return menuArray.size();
}

@Override
public HomeList getItem(int position) {
    return menuArray.get(position);
}

@Override
public long getItemId(int i) {
    return Long.valueOf(menuArray.get(i).id);
}

public void setSelectedPosition(int position) {
    this.selectedPosition = position;
    this.notifyDataSetChanged();
}

@Override
public View getView(final int position, View convertView, ViewGroup viewGroup) {
    ViewHolder holder;
    if (convertView == null) {
        convertView = LayoutInflater.from(context).inflate(R.layout.navigation_list_item, null);
        holder = new ViewHolder();
        holder.layout = (RelativeLayout) convertView.findViewById(R.id.navigation_layout);
        holder.title = (TextView) convertView.findViewById(R.id.navigation_title);
        holder.icon = (TextView) convertView.findViewById(R.id.navigation_icon);
        holder.pmCount = (TextView) convertView.findViewById(R.id.navigation_pmCount);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    HomeList item = getItem(position);
    holder.title.setText(item.title);
    holder.icon.setText(item.icon);

    if (selectedPosition == position) {
        holder.layout.setBackgroundColor(context.getResources().getColor(R.color.navigation_items_selected));
        holder.title.setTextColor(context.getResources().getColor(R.color.white));
        holder.icon.setTextColor(context.getResources().getColor(R.color.white));

    } else {
        holder.layout.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.navigation_bg_selector));
        holder.title.setTextColor(context.getResources().getColorStateList(R.color.black_white_selector));
        holder.icon.setTextColor(Category.getColorByCategory(context, item.category));
    }

    if (item.category == Category.NOTIFICATIONS) {
        int notViewedCount = DataBaseAccess.getInstance().getNotViewedNotificationsCount();
        if (notViewedCount > 0) {
            holder.pmCount.setVisibility(View.VISIBLE);
            holder.pmCount.setText(String.valueOf(notViewedCount));
        } else {
            holder.pmCount.setVisibility(View.GONE);
        }
    } else {
        holder.pmCount.setVisibility(View.GONE);
    }
        return convertView;
}

class ViewHolder {
    RelativeLayout layout;
    TextView title;
    TextView icon;
    TextView pmCount;
}
}

که من از این آداپتر برای منوی کشویی استفاده کرده ام ، در جاهایی از این لیست نیاز بوده تا رنگ منوی انتخاب شده تغییر کند،
یا اینکه در جلوی بعضی آیتم ها اعدادی را نمایش دهم . (نمونه کامل رو قرار دادم شاید قسمت هایی از اون بهتون ایده بده).

به صورت خلاصه برای استفاده از این کلاس نیاز دارید تا متد های زیر را override کنید :

 
getCount()
getItem()
getItemId()
getView()

که مهم ترین آن ها getCount و getView هستند.
معمولا مقادیر اولیه مورد نیاز رو هم با Constructor به کلاس آداپتر می دهیم.

در مثال بالا آرایه ای از نوع ArrayList که مقادیر HomeList داخل آن می باشد را می گیریم .
در متد getCount() سایز لیست را تعیین می کنیم (تعداد آیتم های لیست(در اینجا سایز آرایه ما می باشد)).

در getItem() بسته به مکان (position) مقادیر آرایه را بر می گردانیم.
در getItemId یک id برگردانده شده است .

و مهم ترین متد getView :
در اینجا آیتم های لیست را می سازیم ، به این صورت که ابتدا یک View را از xml  می سازیم (inflate) می کنیم ، سپس آیتم های آن را مقدار

دهی می کنیم .
(برای این کار ابتدا یک layout دلخواه می سازیم ، با شکل و آیتم های دلخواه سپس با کد زیر آن را inflate می کنیم :

 
View convertView = LayoutInflater.from(context).inflate(R.layout.myCustomLayout);

خوب اینکه inflate چیست ، در اندروید زمانی که قصد داشته باشیم یک layout را داخل برنامه نشان دهیم از inflate استفاده می کنیم (ممکن

است بخواهید در زمان اجرای برنامه یک آیتم مثلا یک دکمه به صفحه اضافه کنید ، LayoutInflater به شما این امکان را می دهد)
دیگه نمیدونم چطور این موجود رو معرفی کنم 😀 اگه باز سوالی داشتید در نظرات بپرسید .
بعد از اینکه از inflate استفاده می کنید حتما نیاز خواهید داشت تا به آیتم های داخل layout دسترسی refrence داشته باشید و مقادیر آن را

تغییر یا برای آن ها Listener تعریف کنید ، خوب برای این کار کافیه اون رو در convertView که همین الان inflate کردیم ، find کنید :

 
TextView text = (TextView) convertView.findViewById(R.id.myCustomLayout_textView);

خوب دیگه حالا هر بلایی که می خواید میتونید سرش بیارید 😀
(در زمانی که بخواهید این آیتم ساخته شده را به صفحه ای اضافه کنید بعد از اینکه آن را inflate کردید باید در آن صفحه (مثلا در

LinearLayout که در آن صفحه وجود دارد از addView استفاده کنید :

 
LinearLayout myRootLayout = (LinearLayout) findViewById(R.layout.mainActivity_rootLayout);
myRootLayout.addView(convertView);

بر می گردیم به BaseAdapter :
همان طور که در کد می بینید در getView از یک ViewHolder استفاده شده است ، خوب معمولا برای اینکه آیتم های layout را (آیتم های

layout همان view ها یعنی دکمه ها و تکست باکس ها و … که در layout وجود دارد) کمی مرتب تر کنیم یک کلاس به اسم ViewHolder می

سازیم و در آن آیتم های layout را اضافه می کنیم :

 
class ViewHolder {
    RelativeLayout layout;
    TextView title;
    TextView icon;
    TextView pmCount;
}

مثلا در بالا من در layout خودم از یک RelativeLayout و ۳ TextView استفاده کرده ام ، حالا هر وقت بخوام این هارا مقدار دهی کنم

میدونم که layout من این ۴ آیتم را دارد و با این ۴ آیتم میتونم کار کنم .

بعد از اینکه کمی متوجه مزایای holder شدید حالا این قسمت کد که خیلی مهم هست رو می خوام توضیح بدم :

 
if(convertView==null)

اگر به ورودی های متد نگاه کنید ، یکی از مقادیر ورودی convertView می باشد .
وقتی لیسی ساخته می شود ، مثلا اگر صفحه گنجایش قرار گرفتن ۵ آیتم از لیست را داشته باشد ، در ابتدای کار convertView =null هست اما

بعد اینکه ۵ آیتم ساخته شدند ، زمانی که اسکرول می کنیم تا به پایین یا بالا برویم ، اندروید برای اینکه محاسبات کاهش یابد و سرعت افزایش و

لگ کم شود ، به جای اینکه آیتم جدیدی بسازد ، آخرین آیتم که از صفحه خارج شده را دوباره برمیگرداند تا ما با تغییر دادن فقط مقادیر درون آن

باز از همان آیتم استفاده کنیم و نیازی نباشد که سیستم مجددا یک view را inflate کند .
این شرط به ظاهر ساده به شدت در سرعت اسکرول لیست ها تاثیر می گذارد .

بعد از اینکه convertView==null باشد ابتدا آن را inflate می کنیم ، سپس در همین جا می توانیم refrence ها را هم تعریف کنیم و با

setTag آن را در تگ convertView قرار دهیم تا در دفعه بعدی نیاز نباشد مجددا refrence ها را هم تعریف کنیم ، خوب اینجاست که کلاس

holder خیلی به درد میخوره ، ما همه view هارا در holder گذاشتیم ، حالا کافیه holder رو به عنوان tag به convertView بدهیم.

 
convertView.setTag(holder);

حالا اگه convertView != null باشد ، ما میتونیم holder رو با دستور getTag() پس بگیریم و refrence هارو داشته باشیم .

بعد از این می تونیم مقادیر داخل view ها را تغییر دهیم و شرط ها و listener ها را تعریف کنیم

 
HomeList item = getItem(position);
    holder.title.setText(item.title);
    holder.icon.setText(item.icon);
...

و در آخر این متد باید convertView را return کنیم تا اندروید ، آیتم جدید را به لیست اضافه کند.

امیدوارم مطلب مفید بوده باشه ، فکر می کنم شرح کاملی از BaseAdapter و نحوه استفاده از اون رو داده باشم .
با نظراتون با من در ارتباط باشید تا مطالب جدید و تازه واستون قرار بدهم 🙂
موفق باشید.

برچسب ها:
پست قبلی
پست بعدی

درباره ایلیا عابدینی

برنامه نویس اندروید و کارشناس مهندسی پزشکی، نفر سوم مسابقه برنامه نویسی اندروید http://www.schallenge.ir ، از سال 92 برنامه نویسی اندروید رو شروع کردم و در حال حاضر در شرکت عصر دانش در حال توسعه اپلیکیشن تجارت پی می باشدم ، این وبلاگ رو ساختم تا تجربیات روزانه و مفید خودم رو داخل اون بزارم. رزومه : iact.ir/cv

4 دیدگاه

  1. سلام

    برای افزایش سرعت اسکرول کردن مقدار دهی کرد؟  if(convertView==null)میشه متغیر ها  رو در همون شرط 

    مثل  holder.title.setText(item.title);

    • اگر فقط قرار است یکبار مقدار دهی شود می توان در این شرط گذاشت (مثلا تعیین رنگ بکگراند همه آیتم ها) چون این شرط فقط برای چند آیتم اول اجرا می شود و بعد از آن دوباره از همان آیتم های قبلی استفاده می شود و این شرط false می شود.

  2. فقط یه کلمه میتونم بگم بهت پسر ، حرفه ای ♥ 

  3. مرسى.توضیحاتتون عالى بود

دیدگاهتان را ثبت کنید

آدرس ایمیل شما منتشر نمی شود.علامت دارها لازمند. *

*

رفتن به بالا