ListView will only display the initial items - android

I'm attempting to use a custom ArrayAdapter for a listView in which I have in one of my activities. The quantity of data I am using is quite large, so to rule out that being the issue I hardcoded an ArrayList<ArrayList<String>> to simply pass 8 items to display on my listView, however the same issue has occured where only the initial 4 are being displayed with no ability to scroll to further items.
I am also aware that there are currently no images being displayed on the listView, I intend to link this up after resolving this issue.
This is the main activity which will display the listView in question:
ProductSelectionActivity.java
public class ProductSelectionActivity extends AppCompatActivity {
ListView productListView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_product_selection);
ArrayList<ArrayList<String>> productsList = new ArrayList<ArrayList<String>>();
ArrayList<String> prodIds = new ArrayList<String>();
ArrayList<String> prodNames = new ArrayList<String>();
ArrayList<String> prodCosts = new ArrayList<String>();
ArrayList<String> prodMainImages = new ArrayList<String>();
prodIds.add("id1");
prodIds.add("id2");
prodIds.add("id3");
prodIds.add("id4");
prodIds.add("id5");
prodIds.add("id6");
prodIds.add("id7");
prodIds.add("id8");
prodNames.add("name1");
prodNames.add("name2");
prodNames.add("name3");
prodNames.add("name4");
prodNames.add("name5");
prodNames.add("name6");
prodNames.add("name7");
prodNames.add("name8");
prodCosts.add("cost1");
prodCosts.add("cost2");
prodCosts.add("cost3");
prodCosts.add("cost4");
prodCosts.add("cost5");
prodCosts.add("cost6");
prodCosts.add("cost7");
prodCosts.add("cost8");
prodMainImages.add("image1");
prodMainImages.add("image2");
prodMainImages.add("image3");
prodMainImages.add("image4");
prodMainImages.add("image5");
prodMainImages.add("image6");
prodMainImages.add("image7");
prodMainImages.add("image8");
productsList.add(prodIds);
productsList.add(prodNames);
productsList.add(prodCosts);
productsList.add(prodMainImages);
// Create the listView arrayAdapter
ProductListAdapter arrayAdapter =
new ProductListAdapter(this, R.layout.product_list_items, productsList);
// Set the adapter
productListView = (ListView) findViewById(R.id.products_list);
productListView.setAdapter(arrayAdapter);
}}
The following is the class for the adapter:
ProductListAdapter.java
public class ProductListAdapter extends ArrayAdapter<ArrayList<String>> {
// Initialise list of products
ArrayList<ArrayList<String>> products;
public ProductListAdapter(Context context, int resource, ArrayList<ArrayList<String>> objects) {
super(context, resource, objects);
products = objects;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.product_list_items, parent, false);
}
// Get product listing info with reference to position that has been passed as param
ArrayList<String> prodIds = products.get(0);
String prodId = prodIds.get(position);
ArrayList<String> prodNames = products.get(1);
String prodName = prodNames.get(position);
ArrayList<String> prodCosts = products.get(2);
String prodCost = prodCosts.get(position);
ArrayList<String> prodMainImages = products.get(3);
String prodMainImage = prodMainImages.get(position);
// Getting id for textview and imageview
TextView textViewName = (TextView) convertView.findViewById(R.id.prod_name_text);
TextView textViewCost = (TextView) convertView.findViewById(R.id.prod_cost_text);
// Setting values to ids
textViewName.setText(prodName);
textViewCost.setText("£"+prodCost);
return convertView;
}}
The layout for the ProductSelectionActivity:
activity_product_selection.xml
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ProductSelectionActivity">
<ListView
android:id="#+id/products_list"
android:layout_width="396dp"
android:layout_height="508dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.961" />
</android.support.constraint.ConstraintLayout>
The layout for the adapter:
product_list_items.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:orientation="horizontal"
android:weightSum="100" >
<ImageView
android:id="#+id/prod_main_image"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_weight="60"
app:srcCompat="#color/background_holo_light" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="40"
android:orientation="vertical" >
<TextView
android:id="#+id/prod_name_text"
android:layout_width="278dp"
android:layout_height="60dp"
android:text="#string/prod_name_text" />
<TextView
android:id="#+id/prod_cost_text"
android:layout_width="278dp"
android:layout_height="60dp"
android:text="#string/prod_cost_text" />
</LinearLayout>
</LinearLayout>
I believe the issue lies within the layout files, through process of elimination of other factors that I thought may have been the issue; such as ensuring all data was being passed correctly (I was able to identify this through the Logcat).
If there is anything else that I could clarify then please let me know.

The ListView will display the items that you are passing in the adapter. So you are passing an ArrayList of 4 elements. This is why the ListView only shows 4 items. If you add more elements to the productsList ArrayList then the number of items you can show will increase.
Another thing, just to improve on what you are doing. Instead of creating separate ArrayLists for each product detail separately, just create a model for your Product and load it with data. Then pass a ArrayList to your custom adapter with any number of Product items you want.
class Product {
String productId;
String productName;
String productCost;
String productImage;
Product(String id, String name, String cost, String image) {
productId = id;
productName = name;
productCost = cost;
productImage = image;
}
}
Now in your ProductSelectionActivity just use it like this.
ArrayList<Product> productList = new ArrayList();
productList.add(new Product("id1", "name1", "cost1", "image1");
//Do this for all other products
ProductListAdapter arrayAdapter = new ProductListAdapter(this, R.layout.product_list_items, productList);
// Set the adapter
productListView = (ListView) findViewById(R.id.products_list);
productListView.setAdapter(arrayAdapter);
The final step is to update your adapter to handle an ArrayList of Products
public class ProductListAdapter extends ArrayAdapter<Product> {
// Initialise list of products
ArrayList<Product> products;
public ProductListAdapter(Context context, int resource, ArrayList<Product> objects) {
super(context, resource, objects);
products = objects;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.product_list_items, parent, false);
}
//Get the product item for this position
Product product = products.get(0);
TextView textViewName = (TextView) convertView.findViewById(R.id.prod_name_text);
TextView textViewCost = (TextView) convertView.findViewById(R.id.prod_cost_text);
// Setting values to ids
textViewName.setText(product.productName);
textViewCost.setText("£" + product.productCost);
return convertView;
}
}
Another improvement would be to use a ViewHolder instead of using a simple view.

You can create a Wrapper(POJO) class to hold your product information and use it for your list adapter. It would be a better way to handle by you list rather than using ArrayList<ArrayList<String>>.
First create a model(Pojo) class to hold product information.
class Product {
String prodId;
String prodName;
String prodCost;
String prodMainImage;
public Product(String prodIds, String prodNames, String prodCostsl, String prodMainImages) {
this.prodId = prodIds;
this.prodName = prodNames;
this.prodCost = prodCostsl;
this.prodMainImage = prodMainImages;
}
}
ProductSelectionActivity.java
public class ProductSelectionActivity extends AppCompatActivity {
ListView productListView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_product_selection);
ArrayList<Product> productsList = new ArrayList<>();
productsList.add(new Product("id1", "name1", "cost1", "image1"));
productsList.add(new Product("id2", "name2", "cost2", "image2"));
productsList.add(new Product("id3", "name3", "cost3", "image3"));
productsList.add(new Product("id4", "name4", "cost4", "image4"));
ProductListAdapter arrayAdapter =
new ProductListAdapter(this, R.layout.product_list_items, productsList);
// Set the adapter
productListView = (ListView) findViewById(R.id.products_list);
productListView.setAdapter(arrayAdapter);
}}
ProductListAdapter.java
public class ProductListAdapter extends ArrayAdapter<Product> {
// Initialise list of products
ArrayList<Product> products;
public ProductListAdapter(Context context, int resource, ArrayList<Product> objects) {
super(context, resource, objects);
products = objects;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.product_list_items, parent, false);
}
Product product = products.get(position);
// Getting id for textview and imageview
TextView textViewName = convertView.findViewById(R.id.prod_name_text);
TextView textViewCost = convertView.findViewById(R.id.prod_cost_text);
// Setting values to ids
textViewName.setText(product.prodName);
textViewCost.setText("£"+product.prodCost);
return convertView;
}
}
That's it. It should work properly. Although nowadays, RecyclerView is being used more for its performance and management. This code can be replaced with RecyclerView as well. Let me know if you want to convert it to RecyclerView. I can help you with that.

Man, first of all use RecyclerView and don't worry about size of data. Secondly make a class which will contains your data:
class Data {
int id;
String name;
String imageUrl;
public Data(int id, String name, String imageUrl) {
this.id = id;
this.name = name;
this.imageUrl = imageUrl;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getImageUrl() {
return imageUrl;
}
}
Please, research information about how to use RecyclerView and why RecyclerView is better that ListView.

Set wrap_content to the height of root layout in product_list_items layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:orientation="horizontal"
android:weightSum="100" >
<ImageView
android:id="#+id/prod_main_image"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_weight="60"
app:srcCompat="#color/background_holo_light" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="40"
android:orientation="vertical" >
<TextView
android:id="#+id/prod_name_text"
android:layout_width="278dp"
android:layout_height="60dp"
android:text="#string/prod_name_text" />
<TextView
android:id="#+id/prod_cost_text"
android:layout_width="278dp"
android:layout_height="60dp"
android:text="#string/prod_cost_text" />
</LinearLayout>

Related

Android Customer Array Adapter does not display data

Hi StackOverflow community! I need your help understanding the following behavior:
I tried to implement a ListView for which each view follows the below layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linearLWLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="100">
<TextView
android:id="#+id/noteText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="66.6" />
<LinearLayout
android:id="#+id/linearVLWLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="33.3"
android:orientation="vertical">
<TextView
android:id="#+id/textcolor"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/reminder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textcolor" />
<TextView
android:id="#+id/location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/reminder" />
<TextView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/location" />
</LinearLayout>
Now, when I'm assigning elements to the list, I'm using the below adapter:
public class MyAdapter extends ArrayAdapter<Note> {
private Context mContext;
private int mResource;
public MyAdapter(#NonNull Context context, int resource, ArrayList<Note> objects) {
super(context, resource);
mContext =context;
mResource=resource;
}
public View getView(int position, View convertView, ViewGroup parent){
String text = getItem(position).getText();
String color = getItem(position).getColor();
String location = getItem(position).getLocation();
String reminder = getItem(position).getReminder();
String image = getItem(position).getImage();
Note note = new Note(text,color,location,reminder,image);
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView=inflater.inflate(mResource,parent,false);
TextView nttxt = (TextView) convertView.findViewById(R.id.noteText);
TextView ntcolor = (TextView) convertView.findViewById(R.id.textcolor);
TextView ntrem = (TextView) convertView.findViewById(R.id.reminder);
TextView ntlocat = (TextView) convertView.findViewById(R.id.location);
TextView ntimg = (TextView) convertView.findViewById(R.id.image);
nttxt.setText(text);
ntcolor.setText(color);
ntrem.setText(reminder);
ntlocat.setText(location);
ntimg.setText(image);
Log.i("Convert",convertView.toString());
Log.i("Text",nttxt.toString());
return convertView;
}
}
The final result should be a list of notes together with user preferences and location/reminder.
Please see below the list assignation made on OnCreate method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_explorer);
FloatingActionButton myFab = this.findViewById(R.id.fabAddNote);
myFab.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intentNoteEditor = new Intent(getApplicationContext(), NoteEditor.class);
startActivity(intentNoteEditor);
}
});
ListView notesList = (ListView) findViewById(R.id.listviewNotes);
Note note1 = new Note("Note1","Col1","Reminder1","Location1","Image1");
Note note2 = new Note("Note2","Col2","Reminder2","Location2","Image2");
Note note3 = new Note("Note3","Col3","Reminder3","Location3","Image3");
Note note4 = new Note("Note4","Col4","Reminder4","Location4","Image4");
ArrayList<Note> notesArray = new ArrayList<>();
notesArray.add(note1);
notesArray.add(note2);
notesArray.add(note3);
notesArray.add(note4);
Log.i("Notes",note1.getText().toString());
MyAdapter adapter = new MyAdapter(this,R.layout.list_item,notesArray);
notesList.setAdapter(adapter);
Log.i("Adapter",adapter.getContext().toString());
}
What am I doing wrong?
Any suggestions will be highly appreciated.
Thank you in advance!
You didn't store the list you feed your adapter to a local field.
Here you are passing ArrayList<Note> objects through the adapter constructor, but didn't save it locally to some store.
So, First modify your Adapter to have a filed of ArrayList<Note>
and initialize it in the constructor.
Second, override the adapter getCount() to return the size of your
list.
Third: modify your getView(), to get the Note object of the current
position in the list
public class MyAdapter extends ArrayAdapter<Note> {
private Context mContext;
private int mResource;
private ArrayList<Note> mNotes;
public MyAdapter(#NonNull Context context, int resource, ArrayList<Note> objects) {
super(context, resource);
mContext = context;
mResource = resource;
mNotes = objects;
}
#Override
public int getCount() {
return mNotes.size();
}
public View getView(int position, View convertView, ViewGroup parent){
String text = mNotes.get(position).getText();
String color = mNotes.get(position).getColor();
String location = mNotes.get(position).getLocation();
String reminder = mNotes.get(position).getReminder();
String image = mNotes.get(position).getImage();
// .... continue the rest of code.
Hope this address your issue.

How to access specific row in ListView and operate on the contents of that row?

I have a list view that is populated with an array of objects using a custom adapter and a row layout. The row displays the object's name, price, contains a button for changing the quantity and displays the total based on the quantity selected.
Example of list populated with 3 items
Here's the issue: I want to tell the list view that, for example, when the user clicks the quantity button in the 2nd row, I want to access the price and quantity values in that same row, & display the result in the total cell at the end of that specific row. I can't figure out how to do that. I'm confused because the button element has a single ID in the XML layout, so how do I distinguish, for example, the button in the 2nd row from the button in the 1st or last row since they're all duplicates?
I know the syntax for the OnClickListener method that will carry out the mathematical operation I need, I just don't know where in the program should I implement it. I've tried in the adapter, but only the button in the last row in the list functioned properly, not all of them. I've been searching and googling for a number of days now, and I've seen different approaches but I'm struggling with implementing them.
The best lead I got was about a method called ListView.getChildAt(index), which should return a specific row within the list based on an index, but how do I get the index of the row based on which button was clicked? This is the stackoverflow post where I read on the .getChildAt(index) method
I'll supply the code for my project below:
Code for the ShopActivity.java:
public class ShopActivity extends AppCompatActivity {
ListView listView;
ItemListAdapter adapter;
ArrayList<ShoppingItem> shoppingItems = new ArrayList<ShoppingItem>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.shop_activity);
shoppingItems.add(new ShoppingItem("Drink", "Water Bottle 1.5 ltr", 11));
shoppingItems.add(new ShoppingItem("Drink", "Pepsi 2 ltr", 10));
shoppingItems.add(new ShoppingItem("Drink", "Orange Juice 1.5 ltr", 7));
listView = (ListView) findViewById(R.id.itemListView);
adapter = new ItemListAdapter(this, R.layout.item_layout, shoppingItems);
listView.setAdapter(adapter);
}
Code for the adapter:
public class ItemListAdapter extends ArrayAdapter<ShoppingItem> {
private ArrayList<ShoppingItem> items;
private int layoutResourceId;
private Context context;
ItemHolder holder = new ItemHolder();
public ItemListAdapter(Context context, int layoutResourceId, ArrayList<ShoppingItem> items) {
super(context, layoutResourceId, items);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.items = items;
}
public static class ItemHolder {
public ShoppingItem shoppingItem;
public TextView itemName;
public TextView itemPrice;
public TextView itemQuantity;
public TextView totalPriceNumber;
public ImageButton plusButton;
public ImageButton minusButton;
}
#Override
public int getCount() {
return items.size();
}
#Override
public ShoppingItem getItem(int position) {
return items.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflater.inflate(layoutResourceId, parent, false);
TextView itemName = (TextView) rowView.findViewById(R.id.itemName);
TextView itemPrice = (TextView) rowView.findViewById(R.id.itemPrice);
TextView itemQuantity = (TextView) rowView.findViewById(R.id.itemQuantity);
TextView totalPriceNumber = (TextView) rowView.findViewById(R.id.totalPrice);
ImageButton plusButton = (ImageButton) rowView.findViewById(R.id.plusButton);
ImageButton minusButton = (ImageButton) rowView.findViewById(R.id.minusButton);
holder.itemName = itemName;
holder.itemPrice = itemPrice;
holder.itemQuantity = itemQuantity;
holder.totalPriceNumber = totalPriceNumber;
holder.plusButton = plusButton;
holder.minusButton = minusButton;
rowView.setTag(holder);
} else
holder = (ItemHolder) rowView.getTag();
holder.shoppingItem = items.get(position);
holder.itemName.setText(holder.shoppingItem.getItemName());
holder.itemPrice.setText(Double.toString(holder.shoppingItem.getItemPrice()));
holder.itemQuantity.setText(Integer.toString(holder.shoppingItem.getQuantity()));
holder.totalPriceNumber.setText(Double.toString(holder.shoppingItem.getItemPrice() * holder.shoppingItem.getQuantity()));
final int rowPosition = position;
holder.plusButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.shoppingItem = items.get(rowPosition);
int newQuantity = holder.shoppingItem.getQuantity();
newQuantity++;
holder.shoppingItem.setQuantity(newQuantity);
holder.itemQuantity.setText(Integer.toString(newQuantity));
holder.totalPriceNumber.setText(Double.toString(holder.shoppingItem.getItemPrice() * holder.shoppingItem.getQuantity()));
notifyDataSetChanged();
}
});
return rowView;
}
Code for the row XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp">
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TableRow>
<CheckBox
android:layout_width="25dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center" />
<ImageView
android:id="#+id/imageBar"
android:layout_width="50dp"
android:layout_height="75dp"
android:layout_gravity="center"
android:src="#drawable/drink" />
<TextView
android:id="#+id/itemName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="3"
android:width="0dp" />
<TextView
android:id="#+id/itemPrice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:width="0dp"
android:gravity="center" />
<ImageButton
android:id="#+id/minusButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.3" />
<TextView
android:id="#+id/itemQuantity"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.4"
android:width="0dp"
android:gravity="center" />
<ImageButton
android:id="#+id/plusButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.3" />
<TextView
android:id="#+id/totalPrice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:width="0dp"
android:gravity="center" />
</TableRow>
</TableLayout>
Code for the ShoppingItem object:
public class ShoppingItem {
private String itemType;
private String itemName;
private double itemPrice;
private int quantity = 1;
public ShoppingItem(String itemType, String itemName, double itemPrice, int quantity) {
this.itemType = itemType;
this.itemName = itemName;
this.itemPrice = itemPrice;
this.quantity = quantity;
}
public String getItemType() {
return this.itemType;
}
public void setItemType(String itemType) {
this.itemType = itemType;
}
public String getItemName() {
return this.itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public double getItemPrice() {
return this.itemPrice;
}
public void setItemPrice(double itemPrice) {
this.itemPrice = itemPrice;
}
public int getQuantity() {
return this.quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
I'm new to the Android development scene.
Each of your rows represents a data set. For example you have a data class for an item.
data class Item(name: String, price: Double)
Add a field for the quantity quantity: Int
In the onClick for the plus button, increment the quantity variable for the item. For example like this:
// data set is something like this...
val dataSet = mutableListOf<Item>()
// creating the view for row i...
plusButton.onClick {
dataSet[i].quantity++
notifyItemChanged(i) // dont think this exists for ListView, but you can also just use notifyDataSetChanged, which will invalidate all rows
}
After incrementing the quantity, you trigger the notifyItemChanged method for the row you changed, this will trigger a UI update for the row, which will then represent your current data set.
You should add the onClick listener in the getView method, and instead of i use position to access the item in your data set.
EDIT:
In your getView() method try something like this:
final int rowPosition = position;
plusButton.setOnClickListener(new View.OnClickListener(View v) {
items.get(rowPosition).quantity++;
notifyDataSetChanged();
});

Custom Listview items layouts

I am new to Android development. I am trying to make my custom listview items layout. I want to know how will I give image path if I have a ImageView in may layout.
Activity file where I am populating this ListView
ListView lstItems = (ListView) findViewById(R.id.lstItems);
String[] from = new String[]{"itemname", "productimage"};
int[] to = new int[]{R.id.itemname, R.id.productimage};
List<HashMap<String, Object>> fillMaps = new ArrayList<HashMap<String, Object>>();
for (Item item : objects) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("itemname", item.getName());
map.put("productimage", item.getImages());
fillMaps.add(map);
}
SimpleAdapter adapter = new SimpleAdapter(this, fillMaps, R.layout.shop_listitem_view, from, to);
lstItems.setAdapter(adapter);
Layout file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:id="#+id/itemname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="19dp"
android:layout_marginTop="22dp"
android:text="TextView"
android:textSize="14sp"
android:layout_alignParentTop="true"
android:layout_toEndOf="#+id/productimage" />
<ImageView
android:id="#+id/productimage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="21dp"
app:srcCompat="#drawable/common_full_open_on_phone"
android:layout_alignTop="#+id/itemname"
android:layout_alignParentStart="true" />
</RelativeLayout>
In this case, the SimpleAdapter will not work for you. In first place you have to create a class that represent your business logic:
public class Product {
public String productName;
public String productImage;
}
Second, you have to add the Glide library into your build.gradle (module app) file. Add this line in your dependencies block:
dependencies {
compile 'com.github.bumptech.glide:glide:3.7.0'
}
After that, you have to create your layout file that will be inflated by your Adapter:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/your_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/your_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Now, let's create your Adapter class, it must extends the BaseAdapter class:
public class YourAdapter extends BaseAdapter{
private List<Object> products;
private Context context;
public YourAdapter(Context context, List<Product> products){
this.context = context;
this.products = products;
}
#Override
public int getCount() {
return products.size();
}
#Override
public Object getItem(int position) {
return products.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater li = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = li.inflate(R.layout.your_list_layout, null);//set layout for displaying items
ImageView image = (ImageView) view.findViewById(R.id.your_image_view);//get id for image view
Glide.with(context).load(products.get(position).productImage).into(image); //set the image in your image view
TextView text = (TextView) view.findViewById(R.id.your_text_view);
text.setText(products.get(position).productName);
return view;
}
}
And finally, in your activity you can use it:
//Create a product:
List<Product> p = new ArrayList<>();
Product prod = new Product();
prod.productName = "Name of your product";
prod.productImage = "http://your_image_url";
prod.add(prod);
YourAdapter adapter = new YourAdapter(this, p);
//and finally, set it into your listview:
listview.setAdapter(adater);

Can't scroll ListView inside ListView in Android

While trying to create news feed in my app, I've created custom ListView Adapter. My single ListView item has an ImageView, WebView and ListView. So I have a ListView inside a ListView. The problem is, when I try to scroll the inner ListView, the outer ListView is being scrolled. What should I change to avoid the problem?
My custom adapter:
public class TestCustomAdapter extends BaseAdapter {
private List<String> imageNames = null;
private List<String> descriptions = null;
private List<String> innerLVitems = null;
private LayoutInflater mInflater;
private Context context;
public FirstFragmentLVAdapter(Context context, List<String> imageNames, List<String> descriptions, List<String> innerLVitems) {
this.imageNames = imageNames;
this.descriptions = descriptions;
this.innerLVitems = innerLVitems;
this.context = context;
mInflater = LayoutInflater.from(context);
}
public int getCount() {
return innerLVitems.size();
}
public Object getItem(int position) {
List <String> returnedList = new ArrayList<>();
returnedList.add(imageNames.get(position));
returnedList.add(descriptions.get(position));
returnedList.add(innerLVitems.get(position));
return returnedList;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.firstfragment_listview_item, null);
holder = new ViewHolder();
holder.image = (ImageView) convertView.findViewById(R.id.eventImage);
holder.description = (WebView) convertView.findViewById(R.id.eventDescriptionWV);
holder.LV = (ListView) convertView.findViewById(R.id.LV);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.image.setImageResource(context.getResources().getIdentifier(imageNames.get(position), "drawable", context.getPackageName()));
String webViewText = "<html><body><p align=\"justify\">"+
descriptions.get(position)+"</p></body></html>";
holder.description.loadDataWithBaseURL(null, webViewText, "text/html", "UTF-8", null);
String [] items = innerLVitems.get(position).split("\\s*,\\s*");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(context,
android.R.layout.simple_list_item_1, android.R.id.text1, items);
holder.LV.setAdapter(adapter);
return convertView;
}
static class ViewHolder {
ImageView image;
WebView description;
ListView LV;
}
}
My listview item:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp">
<ImageView
android:id="#+id/eventImage"
android:layout_width="wrap_content"
android:layout_height="125dp"
app:srcCompat="#drawable/autumn" />
<WebView
android:id="#+id/eventDescriptionWV"
android:layout_width="match_parent"
android:layout_height="220dp"
android:layout_below="#id/eventImage"></WebView>
<TextView
android:id="#+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/eventDescriptionWV"
android:text="Text" />
<ListView
android:divider="#null"
android:dividerHeight="0dp"
android:id="#+id/LV"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_below="#id/label" />
To use 2 nested ListViews you sh to use an ExpandableListView : https://developer.android.com/reference/android/widget/ExpandableListView.html.
Using 2 ListViews the Android will always apply the scroll on the first one it finds. The ExpandableListView component is specific for working with sublists within lists.
I was able to find a solution for my case. I needed to add this line to the inner ListView XML:
android:nestedScrollingEnabled="true"
This only works only for Lollipop and up though.
You may want to use RecyclerViewwith NestedScrollView and turn off RecyclerView's nested scrolling. This way you can have multiple scrollable items along same orientation.

Use array adapter with more views in row in listview

I have stumbled upon a problem I can't quite get my head around, so I was hoping perhaps someone here have had the same problem or knew a good way of solving the problem.
I have created a view containing a ListView. This ListView contains two TextView.
The problem is that I don't know where I send the values which are meant to go in the second text view using the ArrayAdapter. Is there a way to send with more information to the ArrayAdapter so that I can feed the "todaysmenu" TextView?
The ArrayAdapter method:
private void createList() {
ListView lv = (ListView) findViewById(R.id.mylist);
String[] values = new String[] { "Android", "Linux", "OSX",
"WebOS", "Windows7", "Ubuntu", "OS/2"
};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.rowlayout, R.id.restaurantname, values);
lv.setAdapter(adapter);
}
The row markup:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/restaurantname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#+id/restaurantname"
android:textSize="23dp" >
</TextView>
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#+id/todaysmenu" />
</LinearLayout>
The activity layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/mylist"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
At the beginning I got everything to work, but when I added the second textfield problems arouse. In advance, thank you for your help!
To achieve this you have to build a custom adapter and inflate your custom row layout. Using ArrayAdapter won't work because
By default this class expects that the provided resource id references
a single TextView. If you want to use a more complex layout, use the constructors that also takes a field id. That field id should reference a TextView in the larger layout resource.
So, your custom adapter class could be somthing like:
public class CustomAdapter extends ArrayAdapter {
private final Activity activity;
private final List list;
public CustomAdapter(Activity activity, ArrayList<Restaurants> list) {
this.activity = activity;
this.list = list;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
ViewHolder view;
if(rowView == null)
{
// Get a new instance of the row layout view
LayoutInflater inflater = activity.getLayoutInflater();
rowView = inflater.inflate(R.layout.rowlayout, null);
// Hold the view objects in an object, that way the don't need to be "re- finded"
view = new ViewHolder();
view.retaurant_name= (TextView) rowView.findViewById(R.id.restaurantname);
view.restaurant_address= (TextView) rowView.findViewById(R.id.textView1);
rowView.setTag(view);
} else {
view = (ViewHolder) rowView.getTag();
}
/** Set data to your Views. */
Restaurants item = list.get(position);
view.retaurant_name.setText(item.getTickerSymbol());
view.restaurant_address.setText(item.getQuote().toString());
return rowView;
}
protected static class ViewHolder{
protected TextView retaurant_name;
protected TextView restaurant_address;
}
}
And your Restaurant.java class could as simple as I describe below:
public class Restaurants {
private String name;
private String address;
public Restaurants(String name, String address) {
this.name = name;
this.address = address;
}
public void setName(String name) {
this.name= name;
}
public String getName() {
return name;
}
public void setAddress(String address) {
this.address= address;
}
public String getAddress() {
return address;
}
}
Now, in you main activity just bind you list with some data, like;
/** Declare and initialize list of Restaurants. */
ArrayList<Restaurants> list = new ArrayList<Restaurants>();
/** Add some restaurants to the list. */
list.add(new Restaurant("name1", "address1"));
list.add(new Restaurant("name2", "address2"));
list.add(new Restaurant("name3", "address3"));
list.add(new Restaurant("name4", "address4"));
list.add(new Restaurant("name5", "address5"));
list.add(new Restaurant("name6", "address6"));
At this point you're able to set the custom adapter to your list
ListView lv = (ListView) findViewById(R.id.mylist);
CustomAdapter adapter = new CustomAdapter(YourMainActivityName.this, list);
lv.setAdapter(adapter);
This is all and it should work nicelly, but I strongly recommend you to google for some better alternatives to implement others Adapters.
You could try this https://devtut.wordpress.com/2011/06/09/custom-arrayadapter-for-a-listview-android/. You have to create a custom class Item with fields you need and extend ArrayAdapter .
I think that your problem is here:
Instead of this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/restaurantname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#+id/restaurantname"
android:textSize="23dp" >
</TextView>
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#+id/todaysmenu" />
</LinearLayout>
Try something like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/restaurantname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test text"
android:textSize="23dp" >
</TextView>
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="test text" />
</LinearLayout>
If that works, then place your text in the /res/val/string folder like so:
<string name="testText">Put your text here...</string>
and then call like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/restaurantname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/testText"
android:textSize="23dp" >
</TextView>
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/testText" />
</LinearLayout>
You would then set the dynamic values like this:
TextView tv = (TextView)findViewById(R.id.restaurantname);
tv.setText(values);
I had to solve the same problem and tried to use the arrayadapter as answered here above, but it didn't work.
Later I succeeded to do it with baseadapter -- this is the adapter:
public class BusinessAdapter2 extends BaseAdapter {
private final ArrayList<Business> myList;
LayoutInflater inflater;
Context context;
public BusinessAdapter2(Context context, ArrayList<Business> myList) {
this.myList = myList;
this.context = context;
inflater = LayoutInflater.from(this.context);
}
#Override
public int getCount() {
return myList.size();
}
#Override
public Object getItem(int position) {
return myList.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView==null) convertView = inflater.inflate(R.layout.business_list_item_2, parent, false);
// assign the view we are converting to a local variable
View v = convertView;
Business b = myList.get(position);
if (b != null) {
TextView name = (TextView) v.findViewById(R.id.textview_name);
TextView address = (TextView) v.findViewById(R.id.textview_address);
TextView description = (TextView) v.findViewById(R.id.textview_description);
TextView discount = (TextView) v.findViewById(R.id.textview_discount);
// check to see if each individual textview is null.
// if not, assign some text!
if (name != null){
name.setText(b.name);
}
if (address != null){
address.setText(b.address);
}
if (description != null){
description.setText(b.description);
}
if (discount != null){
discount.setText(b.discountRate);
}
}
// the view must be returned to our activity
return v;
}
}
this is the Object class I used (Business):
public class Business {
String name,address,description,discountRate;
public Business(){}
public Business(String name,String address,String description,String discountRate){
this.name=name;
this.address=address;
this.description=description;
this.discountRate=discountRate;
}
}
and this is how I populate the listview into the adapter:
ArrayList<Business> businesses2=new ArrayList<Business>(Arrays.asList(for_listview_objects));
adapter_objects =new BusinessAdapter2(
context, // The current context (this activity)
businesses2);
listView.setAdapter(adapter_objects);

Categories

Resources