Custom Adapter For List View

Custom Adapter for List View

public class ListAdapter extends ArrayAdapter<Item> {

private int resourceLayout;
private Context mContext;

public ListAdapter(Context context, int resource, List<Item> items) {
super(context, resource, items);
this.resourceLayout = resource;
this.mContext = context;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

View v = convertView;

if (v == null) {
LayoutInflater vi;
vi = LayoutInflater.from(mContext);
v = vi.inflate(resourceLayout, null);
}

Item p = getItem(position);

if (p != null) {
TextView tt1 = (TextView) v.findViewById(R.id.id);
TextView tt2 = (TextView) v.findViewById(R.id.categoryId);
TextView tt3 = (TextView) v.findViewById(R.id.description);

if (tt1 != null) {
tt1.setText(p.getId());
}

if (tt2 != null) {
tt2.setText(p.getCategory().getId());
}

if (tt3 != null) {
tt3.setText(p.getDescription());
}
}

return v;
}

}

This is a class I had used for my project. You need to have a collection of your items which you want to display, in my case it's <Item>. You need to override View getView(int position, View convertView, ViewGroup parent) method.

R.layout.itemlistrow defines the row of the ListView.

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content" android:orientation="vertical"
android:layout_width="fill_parent">

<TableRow android:layout_width="fill_parent"
android:id="@+id/TableRow01"
android:layout_height="wrap_content">

<TextView android:textColor="#FFFFFF"
android:id="@+id/id"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="id" android:textStyle="bold"
android:gravity="left"
android:layout_weight="1"
android:typeface="monospace"
android:height="40sp" />
</TableRow>

<TableRow android:layout_height="wrap_content"
android:layout_width="fill_parent">

<TextView android:textColor="#FFFFFF"
android:id="@+id/categoryId"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="categoryId"
android:layout_weight="1"
android:height="20sp" />

<TextView android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_weight="1"
android:textColor="#FFFFFF"
android:gravity="right"
android:id="@+id/description"
android:text="description"
android:height="20sp" />
</TableRow>

</TableLayout>

In the MainActivity define ListViewlike this,

ListView yourListView = (ListView) findViewById(R.id.itemListView);

// get data from the table by the ListAdapter
ListAdapter customAdapter = new ListAdapter(this, R.layout.itemlistrow, List<yourItem>);

yourListView .setAdapter(customAdapter);

How to implement a custom adapter with listview?

You should just change your super constructor invoke. Because it receive the layout resource which you gonna inflate. Like this:

public IndustryAdapter(Context context, ArrayList<Industry> industries) {
super(context, android.R.layout.simple_list_item_1);
}

ListView & Custom Adapter dont work Kotlin

To the adapter, it's one item for one view. Your backing List has only one item. Your for loop inside getView() is iterating some collection inside that single item, and setting the value of the same TextView over and over until it gets to the last one.

Since the backing type of your adapter is TestHero, your list view can only show one line item per instance of TestHero. You only have one instance of TestHero.

Based on what you're showing, you should make the backing type of your adapter whatever the type of the list TestHero.legends.all is. In your coroutine, you can pull that list out of your TestHero and pass it to your Adapter. You'll need to make the backing list property mutable.

And like I said in the comments, don't use mutable lists for this. You should start with an empty list.

For example, if the type of this list is Legend, your adapter should look something like:

class HeroesAdapter(): BaseAdapter() {
var heroes: List<Legend> = emptyList()

override fun getCount(): Int = heroes.size

override fun getItem(position: Int): = heroes[position]

override fun getItemId(position: Int) = position

override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view = convertView ?: LayoutInflater.from(parent.context).inflate(R.layout.list_hero_view, parent, false)
val heroText: TextView = view.findViewById(R.id.textHeroView)
val hero = heroes[position]
heroText.text = hero.keys.first()
return view
}
}

And in your Activity, get rid of the listHero property. In your coroutine, after you get your data, do

heroesAdapt.apply {
heroes = data.legends.all
notifyDataSetChanged()
}

Also, consider switching to RecyclerView. ListView is kind of obsolete and I keep expecting them to deprecate it because they have only worked on improving RecyclerView the past several years.

Setting Listener on individual item of custom adapter list view

If your item listener is not working then you can apply this on ListView in xml layout.

android:descendantFocusability="blocksDescendants" 

You can put many clicks listeners if you need in adapter class like

   public class MyAdapter extends ArrayAdapter<Contact> {
Context context;
public MyAdapter(Context context, ArrayList<Contact> users) {
super(context, 0, users);
this.context = context;
}

public View getView(int position, View convertView, ViewGroup parent) {

Contact user = getItem(position);

if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.listviewadapter, parent, false);
}
TextView name = convertView.findViewById(R.id.name);
TextView num = convertView.findViewById(R.id.num);
// Populate the data into the template view using the data object

name.setText(user.name);
num.setText(user.phone_number);
// can set click on name or num
name.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, position + "position clicked", Toast.LENGTH_SHORT).show();
}
});
// can set click on full list item
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, position + "position clicked", Toast.LENGTH_SHORT).show();
}
});
return convertView;
}
}

How to add items dynamically to a custom adapter for ListView

The problem is that your adapter's lfs's field and your activity's elements field both refer to the same List instance. This happens because you pass elements to the ListAdapter constructor, and then simply assign this.lfs = lfs.

So let's look at what happens when you pass elements to updateItems()...

public void updateItems(List<Lf> lfs) {
this.lfs.clear(); // this.lfs and the input lfs are the same list, so this clears both
this.lfs.addAll(lfs); // input lfs is now empty, so addAll() does nothing
this.notifyDataSetChanged();
}

Probably the best thing to do is to create a copy of the list in your adapter's constructor.

this.lfs = new ArrayList<>(lfs);

Now your adapter and activity will reference different lists, so this.lfs.clear() won't accidentally clear out the very list you're passing to it.

List view with custom adapter don't show all items

In Custom_listview_adapter change

@Override
public int getCount(){
return this.spinner_array.length;
}

to

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

Search items from listview with custom adapter

You should implements Filterable in your Adapter

A custom ListView with a custom adapter in Android Studio

At first use ViewHolder pattern. At second extend BaseAdapter not AdapterView. At third delete android:clickable="true" from row.xml. Clickable state must have ListView in method onItemClickListener, not own row.

Updated

For the Customized listview you can use BaseAdapter.

And With Adapter Class you it have some tips to make it smooth , for that you can refer this

Its also about resusability already created row's control instances.For that ViewHolder pattern i prefer to use to hold the objects. Please check this for more detail

Which is missing in your code of the adapter's getView Method.

For more explanation i leave comment in Adapter's getView Method.

Class to hold the details if you are gng to use thn naming convention should be proper
here first the name is "Object" which is wrong.

Activity

private ListView list;
private final ArrayList<RestaurantsDetails> pairs = new ArrayList<RestaurantsDetails>();
private Activity context;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

pairs.add(new RestaurantsDetails("McDonald's", "mcd"));
pairs.add(new RestaurantsDetails("Subway", "mcd"));
pairs.add(new RestaurantsDetails("Pizza Hut", "mcd"));
pairs.add(new RestaurantsDetails("Burger King", "mcd"));

list = (ListView) findViewById(R.id.listview);

AdapterViewCustom adapter = new AdapterViewCustom(this, pairs);
list.setAdapter(adapter);

list.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
@Override
public void onItemClick(android.widget.AdapterView<?> parent,
View view, int position, long id) {
Toast.makeText(getApplicationContext(),
pairs.get(position).name, Toast.LENGTH_LONG).show();
}
});

}

DataLayer Class

/**
* Use proper name For the class. Should not use the name like "Object" or
* the class which is already used by framework
*
*/
public class RestaurantsDetails {

public String name;
public String img;

public RestaurantsDetails(String name, String img) {
this.name = name;
this.img = img;
}

}

Adapter

public class AdapterViewCustom extends BaseAdapter {

private Activity context_1;

private ArrayList<RestaurantsDetails> pairs;

public AdapterViewCustom(Activity context,
ArrayList<RestaurantsDetails> pairs) {
context_1 = context;
this.pairs = pairs;
}

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

@Override
public Object getItem(int position) {
return null;
}

@Override
public long getItemId(int position) {
return 0;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;

if (convertView == null) {
convertView = LayoutInflater.from(context_1).inflate(
R.layout.custom_row, null);
viewHolder = new ViewHolder();
viewHolder.img = (ImageView) convertView
.findViewById(R.id.log_img);
viewHolder.txt = (TextView) convertView
.findViewById(R.id.tv_view);
/**
* At very first time when the List View row Item control's
* instance is created it will be store in the convertView as a
* ViewHolder Class object for the reusability purpose
**/
convertView.setTag(viewHolder);
} else {
/**
* Once the instance of the row item's control it will use from
* already created controls which are stored in convertView as a
* ViewHolder Instance
* */
viewHolder = (ViewHolder) convertView.getTag();
}

viewHolder.txt.setText(pairs.get(position).name);
int id = context_1.getResources().getIdentifier(
pairs.get(position).img, "drawable",
context_1.getPackageName());
viewHolder.img.setImageResource(id);

return convertView;
}

public class ViewHolder {
public final ImageView img;
public final TextView txt;

}
}

Custom Adapter ListView Error

You need to pass Context not ValueEventListener so change adapter as

public customAdapter(/*ValueEventListener*/ Context context, int layoutResource, 
List<UserInformation> userInformationsList) {
super(context, layoutResource, userInformationsList);

}

and remove the cast as well

 customAdapter customAdapterIntent= new customAdapter(/*(ValueEventListener)*/ this,R.layout.userslist,userInformationsList);

where context is required by the layoutinflater or adapter to access the resources when you call getContext()

and also remove setContentView(R.layout.activity_search); from list method, you are doing it twice , so no need


Thank so much, I did as you said and It works but it only list the last user's information

You need to fetch all the users and add them in list because currently you are storing information of last user in as string values and using those values to create list of single user object.

// outside onCreate
List<UserInformation> users = new ArrayList<>();


mRefresh.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

DatabaseReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
listClean();
FirebaseUser user = mAuth.getCurrentUser();
userID = user.getUid();
Lat = dataSnapshot.child("Users").child(userID).child("Coordenates/Rute/Lat").getValue(String.class);
Lng = dataSnapshot.child("Users").child(userID).child("Coordenates/Rute/Lng").getValue(String.class);
DataSnapshot dS = dataSnapshot.child("Coordenate").child(Lat).child(Lng);

for(DataSnapshot Ds : dS.getChildren()) {
Object key = Ds.getKey();
String StringKey = String.valueOf(key);

// fetch the user Object based on key and add it to list
users.add(lidataSnapshot.child("Users").child(StringKey).getValue(UserInformation.class));
}
// now display list with all user information
customAdapter customAdapterIntent= new customAdapter(SearchActivity.this,
R.layout.userslist,
users);
mListView.setAdapter(customAdapterIntent);

}

@Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(SearchActivity.this,"Error 404",Toast.LENGTH_SHORT).show();

}
});
}
});


Related Topics



Leave a reply



Submit