Documente Academic
Documente Profesional
Documente Cultură
Profesor
builder.show();
}
}
android.R.layout.activity_list_item
android.R.id.icon (ImageView)
android.R.id.text1 (TextView)
android.R.layout.simple_expandable_list_item_1
android.R.id.text1 (TextView)
android.R.layout.simple_expandable_list_item_2
android.R.id.text1 (TextView)
android.R.id.text2 (TextView)
http://www.javajirawat.com/2013/03/built-in-android-listview-layouts-part-1.html
android.R.layout.simple_list_item_1
android.R.id.text1 (TextView)
android.R.layout.simple_list_item_2
android.R.id.text1 (TextView)
android.R.id.text2 (TextView)
http://www.javajirawat.com/2013/03/built-in-android-listview-layouts-part-1.html
android.R.layout.simple_list_item_activated_1
android.R.id.text1 (TextView)
android.R.layout.simple_list_item_activated_2
android.R.id.text1 (TextView)
android.R.id.text2 (TextView)
http://www.javajirawat.com/2013/03/built-in-android-listview-layouts-part-2.html
android.R.layout.simple_list_item_checked
android.R.id.text1 (CheckedTextView)
android.R.layout.simple_list_item_multiple_choice
android.R.id.text1 (CheckedTextView)
http://www.javajirawat.com/2013/03/built-in-android-listview-layouts-part-2.html
android.R.layout.simple_list_item_single_choice
android.R.id.text1 (CheckedTextView)
android.R.layout.two_line_list_item
android.R.id.text1 (TextView)
android.R.id.text2 (TextView)
http://www.javajirawat.com/2013/03/built-in-android-listview-layouts-part-2.html
Pentru exemplul nostru, am putea crea o listă de contacte care
să aibă două feluri de rânduri:
Header cu steagul și numele țării
Detalii despre companie
Vom cere de la server contactele și vom construi o listă de
elemente care va fi transmisă la adaptor pentru a construi lista
de afișat.
Mai jos aveți implementarea unor clase exemple
public class JobContact {
public class Country {
public JobContact() {
// A default constructor is required.
String countryCode;
}
String name;
private int id;
private String name;
public Country(String countryCode) {
private String email;
this.countryCode = countryCode.toLowerCase();
private String description;
this.name = getNameByCountryCode(countryCode);
private String country;
}
public int getId() {
public String getName(){
return id;
return name;
}
}
public String getName() {
return name;
public int getImageRes(Context ctx){
}
return ctx.getResources().getIdentifier(countryCode, "drawable", ctx.getPackageName());
public String getDescription() {
}
return description;
}
public static String getNameByCountryCode(String countryCode){
public String getCountry() {
if (countryCode.equals("ES")){
return country;
return "Spain";
}
} else if (countryCode.equals("GB")){
public String getEmail() {
return "Great Britain";
return email;
} else {
}
return "Unknown";
}
}
}
}
Putem folosi Volley
StringRequest stringRequest = new StringRequest(
Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Gson gson = new Gson();
Type listType = new TypeToken<List<JobContact>>(){}.getType();
List<JobContact> listContacts = gson.fromJson(response, listType);
MAApplication.getInstance().getRequestQueue().add(stringRequest);
public class JobContactsAdapter extends BaseAdapter {
private List<Object> mItemsList;
implementate }
mContext = context;
@Override
public int getCount() {
Avem nevoie de Context pentru încărcarea }
return mItemsList.size();
List<Object> mListItems;
}
// Required empty public constructor
el }
currentCountry = jobContact.getCountry();
mListItems.add(new Country(currentCountry));
mListItems.add(jobContact);
Acesta deja încarcă un view având un }
setListAdapter(new JobContactsAdapter(mListItems,getActivity()));
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.i("test", error.toString());
}
}
);
MAApplication.getInstance().getRequestQueue().add(stringRequest);
}
}
Numărul de rânduri dintr-o listă poate fi variabil, chiar foarte
mare
Când derulăm o listă, view-urile care nu sunt vizibile, pe fiecare
parte a ecranului, se recomandă a fi refolosite
Astfel se salvează timpii de încărcare a view-urilor
Poate fi diferența dintre o listă fluentă și una sacadată
Metoda getView() primește ca un parametru, o vedere care se
poate recicla sau null dacă nu există view-uri de reciclat
Dacă avem mai multe tipuri de view-uri, Android verifică intern
tipul corect și trimite o instanță corespunzătoare, dacă există,
altfel trimite null
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
switch (getItemViewType(i)){
case (0) :
if (view == null) {
view = View.inflate(mContext, R.layout.row_job_country, null);
}
Country country = (Country) mItemsList.get(i);
((TextView) view.findViewById(R.id.rowJobCountryTitle)).
setText(country.getName());
((ImageView) view.findViewById(R.id.rowJobCountryImage)).
setImageResource(country.getImageRes(mContext));
break;
case (1) :
if (view == null) {
view = View.inflate(mContext, R.layout.row_job_contact, null);
}
JobContact company = (JobContact) mItemsList.get(i);
((TextView) view.findViewById(R.id.rowJobContactName)).
setText(company.getName());
((TextView) view.findViewById(R.id.rowJobContactEmail)).
setText(company.getEmail());
((TextView) view.findViewById(R.id.rowJobContactDesc)).
setText(company.getDescription());
}
return view;
}
Pentru a elimina căutarea de fiecare dată a elementelor din
view-urile reciclate se poate aplica un tipar numit ViewHolder
Se creează o clasă numită ViewHolder care va menține
referințele la componente
Putem asocia o instanță de clasă (în acest caz ViewHolder) cu un rând
prin apelul la metoda setTag()
Putem accesa acel tag prin metoda getTag()
Putem asocia mai multe tag-uri la un view, specificând o cheie pentru
respectivul tag setTag(key, obj)
Putem accesa acel tag prin specificarea cheii: getTag(key)
@Override private class CountryViewHolder{
public View getView(int i, View view, ViewGroup viewGroup) {
switch (getItemViewType(i)){ public TextView name;
case (0) : public ImageView flag;
CountryViewHolder holderC;
if (view == null){ public void bindView(Country country){
view = View.inflate(mContext, R.layout.row_job_country,null); this.name.setText(country.getName());
holderC = new CountryViewHolder(); this.flag.setImageResource(country.getImageRes(mContext));
holderC.name = (TextView) view.findViewById(R.id.rowJobCountryTitle); }
holderC.flag = (ImageView) view.findViewById(R.id.rowJobCountryImage);
view.setTag(holderC); }
} else {
holderC = (CountryViewHolder) view.getTag(); private class CompanyViewHolder{
}
holderC.bindView((Country)mItemsList.get(i)); public TextView name;
break; public TextView email;
case (1) : public TextView desc;
CompanyViewHolder holder;
if (view == null){ public void bindView(JobContact company){
view = View.inflate(mContext, R.layout.row_job_contact,null); this.name.setText(company.getName());
holder = new CompanyViewHolder(); this.email.setText(company.getEmail());
holder.name = (TextView) view.findViewById(R.id.rowJobContactName); this.desc.setText(company.getDescription());
holder.email = (TextView) view.findViewById(R.id.rowJobContactEmail); }
holder.desc = (TextView) view.findViewById(R.id.rowJobContactDesc);
view.setTag(holder); }
} else {
holder = (CompanyViewHolder) view.getTag();
}
holder.bindView((JobContact)mItemsList.get(i));
}
return view;
}
Pentru operații de durată, cum ar fi încărcarea de imagini în
fiecare view, trebuie să creăm un AsyncTask în getView()
Pentru încărcarea de imagini putem implementa de exemplu o clasă
LoadImageAsyncTask derivată din AsyncTask
Aceasta va primi ca și parametri:
URL-ul imaginii
Referință la viewHolder-ul corespunzător
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_job_offer, parent, false);
return new MyViewHolder(v);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.textViewName.setText(mOfferList.get(position).getTitle());
holder.textViewDescription.setText(mOfferList.get(position).getDescription());
}
@Override
public int getItemCount() {
return mOfferList.size();
}
public ListFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_list, container, false);
return view;
}
public void retrieveJobOffers(){
String url = “...";
StringRequest stringRequest = new StringRequest(
Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Gson gson = new Gson();
Type listType = new TypeToken<List<JobOffer>>(){}.getType();
mListItems = gson.fromJson(response, listType);
JobOffersAdapter adapter = new JobOffersAdapter(mListItems);
mRecyclerView.setAdapter(adapter);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
}
);
MAApplication.getInstance().getRequestQueue().add(stringRequest);
}
Putem implementa tratarea de evenimente pe elementele RecyclerView
Click listener – pentru a deschide view-ul de detalii
Longclick listener – pentru a șterge un element
Pe ListView era destul de simplu
ListView.setOnItemClickListener
ListView.setOnItemLongClickListener
Pentru RecyclerView nu este chiar așa de simplu, există două abordări
Crearea unei clase care implementează RecyclerView.OnItemTouchListener și care
apelează metoda addOnItemTouchListener de pe RecyclerView
Avantajul acestei abordări este posibilitatea refolosirii, respectiv implementarea logicii la nivelul
activității sau a fragmentului și nu a view-ului
Gestionarea evenimentelor în interiorul ViewHolder-ului
Avantajul este că putem detecta evenimente pe diferite componente din interiorul view-ului
asociat cu un rând
mRecyclerView.addOnItemTouchListener( public class MyRecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
new MyRecyclerItemClickListener( public static interface OnItemClickListener {
getActivity(), mRecyclerView, public void onItemClick(View view, int position);
new MyRecyclerItemClickListener.OnItemClickListener() { public void onItemLongClick(View view, int position);
@Override }
public void onItemClick(View view, int position){
// ... private OnItemClickListener mListener;
} private GestureDetector mGestureDetector;
@Override
public void onItemLongClick(View view, int position){ public MyRecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
// ... mListener = listener;
} mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener()
} {
) @Override
); public boolean onSingleTapUp(MotionEvent e) {
return true;
@Override
gesturilor }
});
@Override
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
View child = view.findChildViewUnder(e.getX(), e.getY());
if(child != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
mListener.onItemClick(child, view.getChildPosition(child));
}
return false;
}
@Override
public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
//Empty
}
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener{
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.rowJobOfferTitle :
//Click
break;
}
}
@Override
public boolean onLongClick(View view) {
mOfferList.remove(getPosition());
notifyItemRemoved(getPosition());
return true;
}
}
În cazul în care avem mai multe tipuri de elemente într-o listă, atunci și în
acest caz trebuie implementată metoda getItemViewType()
În loc să specificăm tipul concret de ViewHolder pentru adaptorul nostru,
vom specifica tipul generic
RecyclerView.Adapter<RecyclerView.ViewHolder>
Trebuie implementate atâtea tipuri de ViewHolder-e câte tipuri de
elemente avem
În onCreateViewHolder în funcție de viewType creăm ViewHolder-ul
corespunzător
În onBindViewHolder, pentru a afla tipul ViewHolder-ului putem apela
holder.getItemViewType() și în funcție de acesta să facem cast la tipul
concret și să inițializăm corect elementele de interfață