0

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.

halfer
  • 19,824
  • 17
  • 99
  • 186
MotorByte
  • 9
  • 5
  • Add `holder.amountButton.setFocusable(false);` in your getView adapter method. – grabarz121 Oct 28 '17 at 22:48
  • @grabarz121 I tried that, unfortunately it didn't work. Still only the last row is the one that displays the correct total, all the rows before it make no changes. I added that line of code in the if (convertView == null) section of the code if that helps clarify anything. Is there anything I'm doing wrong? Either way I appreciate your feedback my friend. – MotorByte Oct 28 '17 at 23:14
  • Your `com.cepheuen.elegantnumberbutton.view.ElegantNumberButton` has property `android:clickable="false"`, remove this line and this should work. I'm using something similar in my actual project, and this works. – grabarz121 Oct 28 '17 at 23:46
  • @grabarz121 I actually started off without that property, but the button ended up crashing the application whenever I clicked on the middle part of it [not the - or + parts]. Could you tell me how do you link the button in your project to every row correctly so all the buttons function in the end? – MotorByte Oct 29 '17 at 00:22

1 Answers1

1

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();
});
damian
  • 2,001
  • 20
  • 38
  • First off let me thank you for your feedback my friend. I did as you advised & added a quantity instance variable within the object class that contained the price & name. The problem is when I tried to modify the code in the adapter & add the onClickListener to the plusButton, I couldn't write the syntax you gave me. – MotorByte Oct 29 '17 at 19:05
  • I've added an example in Java that fits more your current code, maybe this helps. – damian Oct 29 '17 at 19:12
  • I tried that code you wrote me, but it wouldn't accept the syntax for ".quantity++;". I think you have the right idea in mind, I modified my code above in the getView() towards the end, I also added the code for the ShoppingItem object I'm using. Unfortunately with these changes it still won't work. The quantity numbers aren't increasing when I hit the plusButton. Do you have any idea why it won't? – MotorByte Oct 29 '17 at 19:31
  • You should re-think the usage of `setQuantity(+1)`, this is not how you would want to use it. You're thinking of a function like `addQuantity`. – damian Oct 29 '17 at 19:34
  • I tried using different syntax for adding 1 to the quantity & updated it above in the getView() section in the adapter code. The code now works, but only for the last row in the list. The rows above it show no response when I click the plusButton. Am I not identifying the rows correctly? – MotorByte Oct 29 '17 at 19:49