Shopper App | Show Purchases #12

A lot of techniques and principles comes together when it comes to load the current purchases from the webservice, display it in a user-friendly way on the smartphone and provide a navigation like ‘pagination’. On this screen the user has  the possibility to display the current purchases and the items of each purchase. Moreover the information which groupmembers are participants of the purchase is also interesting.  Our Activity for this purpose is implemented as a ListActivity, where every row represents a Purchase. The user can click on a purchase  row and it expands to a more detailed view. The Listview  receives its data from a custom ArrayAdapter again, but the getView() method will be a little more complicated, since we have to construct a more complex layout.


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

			// INFLATE XML LAYOUT
			LayoutInflater inflater = context.getLayoutInflater();
			View rowView = inflater.inflate(R.layout.show_purchases_row, null, true);

			// GETTING VIEWS
			TextView txtItemLabel = (TextView) rowView.findViewById(R.id.lbl_purchase_owner);
			TextView txtItemPrice = (TextView) rowView.findViewById(R.id.lbl_purchase_date);

			// SETTING VIEWSCONTENT
			txtItemLabel.setText(purchases.get(position).getOwner());
			txtItemPrice.setText(purchases.get(position).getDate());

			// HIDE TABLELAYOUT (detailed informations of one purchase)
			TableLayout tl = (TableLayout) rowView.findViewById(R.id.purchase_details);

			// GETTING ITEMS
			List<Item> items = (ArrayList<Item>) purchases.get(position).getItems();

			// ITERATE OVER ITEMS & CREATE TABLE ROWS
			Double total_amount = 0.0;
			for (Item i : items) {
				total_amount += i.getPrice();

				// CREATING A NEW ROW TO BE ADDED
				TableRow tr = new TableRow(ShowPurchasesActivity.this);
				TextView tv = new TextView(ShowPurchasesActivity.this);
				tv.setText(i.getLabel());
				tv.setPadding(10, 0, 0, 0);

				TextView tv2 = new TextView(ShowPurchasesActivity.this);
				tv2.setText(i.getPrice().toString());
				tv2.setGravity(Gravity.RIGHT);

				// ADD TEXTVIEWS TO ROW
				tr.addView(tv);
				tr.addView(tv2);

				// ADD ROW TO TABLE LAYOUT
				tl.addView(tr, new TableLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
			}

			// TOTAL
			TableRow tr_total_amount = new TableRow(ShowPurchasesActivity.this);

			TextView placeholder = new TextView(ShowPurchasesActivity.this);
			placeholder.setText("");
			placeholder.setPadding(10, 0, 0, 0);

			TextView lbl_total_amount = new TextView(ShowPurchasesActivity.this);
			lbl_total_amount.setText("TOTAL: EUR " + total_amount);
			lbl_total_amount.setGravity(Gravity.RIGHT);

			tr_total_amount.addView(placeholder);
			tr_total_amount.addView(lbl_total_amount);
			tl.addView(tr_total_amount, new TableLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
					LayoutParams.WRAP_CONTENT));

			// EMPTY ROW
			TableRow tr_empty = new TableRow(ShowPurchasesActivity.this);
			TextView empty = new TextView(ShowPurchasesActivity.this);
			empty.setText(" ");
			tr_empty.addView(empty);
			tl.addView(tr_empty, new TableLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));

			// PARTICIPANTS ROW
			TableRow tr_participants = new TableRow(ShowPurchasesActivity.this);
			TextView lbl_participants = new TextView(ShowPurchasesActivity.this);

			String p = "Participants: \n";
			for (String name : purchases.get(position).getParticipants()) {
				p += name + ", ";
			}
			p = p.substring(0, p.length() - 2);

			lbl_participants.setText(p);
			lbl_participants.setPadding(10, 0, 0, 0);
			tr_participants.addView(lbl_participants);
			tl.addView(tr_participants, new TableLayout.LayoutParams(LayoutParams.FILL_PARENT,
					LayoutParams.WRAP_CONTENT));

			// WE HAVE TO SET THE VISIBILITY FOR THE LINES IN THE GETVIEW METHOD
			// WHICH IS CALLED EVERY TIME, FOR EVERY LINE WHEN USER INTERACTS
			// WITH THE LIST
			tl.setVisibility(states.get(position));

			return rowView;
		}

The expandation of each row in the list is implemented as a TableLayout which becomes visible when the user clicks on the respective row. This  TableLayout is filled up dynamical with the content we want to display. These are mainly TextViews in the respective TableRows. What we need is a data-structure which stores the state of each row (expanded or not). I am using a simple ArrayList which stores Integers.

Retrieving data from the Webservice (getting the purchases)

This is no surprise anymore. I implemented it as an asynchronous Task. As discussed in a previous posting we need a way to provide a kind of pagination. It is no good idea to load the whole purchases from the server because after a while this can be a big overhead. So we simplymake arest call to http://1.latest.shopper-server.appspot.com/rest/purchases/get?group=g1&number=4&page=1 where page will be incremented on each time the user clicks on the Next-Button and decremented otherwise. So everytime when the user clicks on one of the navigation-buttons (prev and next) a rest-call is made to this URL. Later we can think about a little optimization. For example it would be a nice idea to load the purchases of the current requested page AND the purchases  of the next while caching the purchases of the previous. This way there is no need to make a rest-call each time when the user clicks “next” or “prev” and so the UI would be a little faster. But for now this optimization is not implemented.

On the top of the screen there is a little TextView displaying the current page, so that the user is informed about the current “position”. Moreover the user get informed about the loading-progress in form of a circle loading animation at the right upper corner of the screen. Let’s take a look at a sample screen:

This screen shows just  two purchases per page. Of course it can and will be more. Since the activity is implemented as ListActivity, displayed purchases are  scrollable so, theoretical we can also display all purchases in one page.

Main Navigation through the shopper app

As you can see, there is no “main-menu” anymore. I decided to realize the navigation through the main functionalities of the shopper app with this nice Tabs. A socalled TabHost is used for it. There were not many things i had to change, because every Tab-Content is an Activity itself. The main funcionalities of the apps are: Showing Purchases, Creating  Purchases and showing a member statistic of the current group.

User Stats

The activity inside the “User Stats” gets its informations (saldo, dues and expenses) from the following URL: http://1.latest.shopper-server.appspot.com/rest/members/getGroupStat which provides us with a simple XML file containing all these informations.

What’s interesting on this activity, is  the corner-rounded rectangles for each row. These shapes are automatically stretched to the size which the containing TextView needs. Also when the user flips the phone the shapes are stretched over the whole width. How does this work? To realize this, I make use of so-called NinePatchDrawables, which are stretchable bitmap images, which Android will automatically resize to accommodate the contents of the View in which you have placed it as the background.

[...]A NinePatch drawable is a standard PNG image that includes an extra 1-pixel-wide border. It must be saved with the extension .9.png, and saved into the res/drawable/ directory of your project.The border is used to define the stretchable and static areas of the image. You indicate a stretchable section by drawing one (or more) 1-pixel-wide black line(s) in the left and top part of the border. (You can have as many stretchable sections as you want.) The relative size of the stretchable sections stays the same, so the largest sections always remain the largest.[...]

Here our NinePatchDrawable image defines one stretchable area with the left and top lines and the drawable area with the bottom and right lines. To learn more about NinePatch images please go to the Android Developer Site .

See you next time in the 13th post.

cheers,

bernd

, , , ,
  • Delicious
  • Facebook
  • Digg
  • Reddit
  • StumbleUpon
  • Twitter

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>