Interpreting item click in ListView - android

I'm working on my first Android project, and I created a menu via the XML method. My activity is pretty basic, in that it loads the main layout (containing a ListView with my String array of options). Here's the code inside my Activity:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// allow stuff to happen when a list item is clicked
ListView ls = (ListView)findViewById(R.id.menu);
ls.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// #todo
}
});
}
Within the onItemClick callback handler, I'd like to check which item was clicked, and load a new menu based upon that.
Question 1: How do I go about figuring out which item was clicked? I can't find any straightforward examples on retrieving/testing the id value of the clicked item.
Question 2: Once I have the id value, I assume I can just call the setContentView method again to change to another layout containing my new menu. Is that correct?

I'm working on my first Android
project, and I created a menu via the
XML method.
Actually, Android has a separate concept of menus, so I'd be a bit wary about describing your UI in those terms.
How do I go about figuring out which
item was clicked?
If you are using an ArrayAdapter, the position parameter passed to onItemClick() is the index into your array.
I assume I can just call the
setContentView method again to change
to another layout containing my new
menu. Is that correct?
Yes, though there may be better approaches to the UI that will be more Android-y. Most Android applications do not start off with some sort of multi-layer navigation before you actually get to do something.

Related

What's the correct way of displaying ViewPager after associated ListView's item click?

I'm a beginner in Android, so I apologize for the mistakes and I'd appreciate any constructive criticism.
I'm writing a basic application with a ListView of images, and when the user clicks on an item in the list, I want to display that image in a ViewPager, where the user can swipe back and forth to browse the whole list of images. Afterwards when the user presses the back button, I want to switch back to the ListView.
I manage the business logic in the MainActivity, which uses MainActivityFragment for the ListView and ImageHolderFragment for ViewPager.
The simplified code so far is as follows:
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListItems = new ArrayList<>();
mListItemAdapter = new ListItemAdapter(this, R.layout.list_item, R.id.list_item_name, mListItems);
mListView = (ListView) findViewById(R.id.list_view_content);
mListView.setAdapter(mListItemAdapter);
mDeletedListItems = new ArrayList<>();
mViewPager = (ViewPager) getLayoutInflater().inflate(R.layout.image_display, null, true);
mImageAdapter = new ImageAdapter(getSupportFragmentManager(), mListItems);
mViewPager.setAdapter(mImageAdapter);
mViewPager.setOffscreenPageLimit(3);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mViewPager.setCurrentItem(position);
setContentView(mViewPager); // TODO: this is very wrong!
}
});
loadImages();
noContentText = (TextView) findViewById(R.id.no_content_text);
if (mListItems.isEmpty()) {
noContentText.setText(R.string.no_images);
} else {
mImageAdapter.notifyDataSetChanged();
}
}
Although this does work to some extent, meaning that it manages to display the ViewPager when an item in the list is clicked, there are two things about it ringing the alarm bells:
I've read that calling setContentView() for the second time in the same class is pretty much a sin. Nobody explained me why.
The back button doesn't work in this case. When it's pressed, the application is terminated instead of going back to the list view. I believe this is connected to the first point.
I would appreciate any help, explanations if my idea is completely wrong, and if my case is hopeless, I'd like to see a successful combination of ListView and ViewPager with transitions between each other.
Your activity already has R.layout.activity_main set as content view, which rightly displays the list view - that's what the responsibility of this activity is as you defined it. If we want to change what's shown on the screen, we should use a different instance of a building block (activity or fragment) to display the view pager images.
To say the least, imagine if you wanted to change the view to a third piece of functionality or UI, or a fourth... it would be a nightmare to maintain, extend and test as you're not separating functionality into manageable units. Fields that are needed in one view are mixed with those needed in another, your class file would grow larger and larger as each view brings its click listeners, callbacks, etc., you'd also have to override the back button so it does what you want - it's just not how the Android framework was designed to help you. And what if you wanted to re-use UI components in different contexts whilst tapping in to the framework's activity lifecycle callbacks? That's why fragments were introduced.
In your case, the list view could continue to run in your MainActivity and in your click listener, onItemClick you could start a new activity that will hold a viewPager:
Intent i = new Intent(MainActivity.this, MyLargePhotoActivityPager.class);
i.putExtra(KEY_POSITION, position);
// pass the data too
startActivityForResult(i, REQUEST_CODE);
Notice how you could pass the position to this activity as an int extra, in order for that second activity to nicely set the viewPager to the position that the user clicked on. I'll let you discover how to build the second activity and put the ViewPager there. You also get back button functionality assuming your launch modes are set accordingly, if needed. One thing to note is that when you do come back to the list View, you'd probably want to scroll to the position from the view pager, which is why you could supply that back as a result via a request code. The returned position can be supplied back to the list view.
Alternatively, you could use the same activity but have two fragments (see the link further above) and have an equivalent outcome. In fact, one of your fragments could store the list view, and the second fragment could be a fullscreen DialogFragment that stores a viewPager, like a photo gallery (some details here).
Hope this helps.
I've read that calling setContentView() for the second time in the
same class is pretty much a sin. Nobody explained me why.
Well, you kind of get an idea as to why.
When you use setContentView() to display another 'screen' you do no have a proper back stack.
You also keep references to Views (like mListView) that are not visible anymore and are therefore kind of 'useless' after you setContentView() for the second time.
Also keep in mind orientation changes or your app going to the background - you'll have to keep track of the state that your Activity was in which is way more complicated than it has to be if you have one Activity that does two different things.
You won't be arrested for doing things like you do right now, but it's just harder to debug and keep bug free.
I'd suggest using two different Activities for the two different things that you want to do, or use one Activity and two Fragments, swapping them back and forth.
If you insist on having it all in one Activity you need to override onBackPressed() (called when the user presses the back button) and restore the first state of your Activity (setContentView() again, pretty much starting all over).

Individual IDs for listeners using a custom ListView

I'm rather new to the Android SDK, and I recently started developping a small application. The application centers around a menu, which is implemented using a custom ListView. I used this guide as a reference in order to build my model classes and my adapter. The author also published the code he used on GitHub, here. My result is rather close from the original one, the screen below is from the author's blog post:
I successfully set up my menu, and now comes the time when I need to connect every item of the list to the listener so that I can handle clicks. In order to keep it simple, I had my activity implement OnClickListener:
public class MenuActivity extends ListActivity implements View.OnClickListener
{
#Override
public void onClick(View v) {
// ...
}
}
I was also able to connect my menu items to this method through my menu items' XML files:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="onClick"
android:id="#+id/menu_item_layout">
Now, whenver I click on one of my list items, I enter the onClick method. However, once I'm there, I can't find a way to distinguish an item from other. As you can see, I applied my click event to their layouts, so that it is triggered when I click an item in it (my texts).
However, since all my items share the same XML layout, they also seem to share the same ID: #id/menu_item_layout. Because of that, I can't do the usual...
public void onClick(View v) {
switch(v.getId()){
case R.id.myId: /* ... */ break;
case R.id.myId2: /* ... */ break;
// ...
}
}
Given this "custom list" implementation, is there a way I could distinguish a click on Menu item1 from a click on Menu item 2?
An OnClickListener will not function as you expect with a ListView. However, the ListActivity class provides the onListItemClick() method, that is implemented as follows:
#Override
protected void onListItemClick(ListView l, View v, int position, long id)
{
}
The position parameter will hold the index in the underlying data list corresponding to the item clicked.
When you create a View for a list item in your ListAdapter you can set tag on that view using View#setTag. Put there something which can distinguish one list item from another i.e. position in adapter. Then use View.getTag to get this unique identifier in onClick listener.
What i think is, there are two ways to do this:
First:
Add clicklistener to the view inside the getview method, that way you would also be having the position(remember to initialize a final int to the position inside getView and use that int inside your clickListener)
Second:(not guaranteed if it will work)
Add a tag to every textView inside getView and store the position in that textView. ex:
textView.setTag(new Integer(int position));
and then fetch that position in the onClick method of yours

need to reload mainActivity controller on click of button located in customized listview

To make my question more understandable let me start with an image of my view.
I have an xml file named Menu, that has customized list view in it. I have created another xmlview named MenuCell as below.
Now tapping on add button I'm adding Item to the cart. which is working perfectly fine except not updating value of a cart (top right corner) on click event. But If I navigate to different view and come back to this view at this point I'm getting number of items added in the cart reflected properly. So How Can I reload my controllerview when I tap in my arradepter view's ImageButton.
this is my adapter code
holder.imageButton1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
addItem(position);
notifyDataSetChanged();
}
});
void addItem(int position) {
count++;
}
Where count is item added count.
If anyone can tell How am I able to reflect this count of my arrayadpter class to my other controller class that holds actual list view.
Any Help will be appreciated
Thanks in advance.
You need to use callback feature to get notified to your activity , hence add button is part of list component so you can update your list view.
Here are few links for understanding of call back using interface
http://cleancodedevelopment-qualityseal.blogspot.in/2012/10/understanding-callbacks-with-java.html
http://stackoverflow.com/questions/11577695/what-is-a-call-back-interface-in-java
After :
notifyDataSetChanged();
just add:
YourList.invalidateViews();
YourList.scrollBy(0, 0);
Send the reference of your controller to your list adapter class. In the controller I guess you have a method that computes some data and after that call update the view that holds cart data summary. Just make sure that update is on UI thread.
Your List is not refreshing at the instant because you have to refresh data of your adapter and then call notifyDataSetChanged();
Suppose You have the data in an array which is visible in textview.Then In your function addItem add the data into ur array and then call notifyDataSetChanged();
This will immediately tell the list view that watever data it is containing is changed so time to refresh.
If you can paste more of ur adapter code i can be helpful

Android: ListView, at the same time remembering and forgetting its getCheckedItemPosition after rotation/configuration change

I really can't make this up so I'd be thankful for any hint. I must make some mistake here (4.1.2).
I have an Activity which, in onCreate(), sets up a subclassed ArrayAdapter for ListView items which render as a Checkable ViewGroup.
The Activity already utilizes a NonConfiguration mechanism to re-build the Adapter upon orientation change. However, it's currently not storing the ListView's getCheckedItemPosition() because I feel it shouldn't be necessary (details below).
Interestingly, what I'm observing is the following.
The Activity is rendered.
The user checks a ListView item.
The ListView item is displayed in a checked state.
The onItemClickListener calls getCheckedItemPosition() for the ListView and gets a correct result.
The user changes the screen orientation.
onCreate() re-builds the 'ListView' and it displays just like before (after onCreate(); see below).
onCreate() calls getCheckedItemPosition() and gets -1 despite the ListView showing the correcly checked item
Upon further examination, the following details emerge.
onCreate():
get ListView resource
build MyAdapter
set MyAdapter as adapter for ListView
getCheckedItemPosition() returns -1
after onCreate():
MyAdapter.getView() is being called
CheckableViewGroup.setChecked() is called with the correct checked value
the last two steps will be repeated for all items
As said before, I'm relying on the Android feature that View objects save their state if they have an ID assigned. I'd say this is the case since there must be some object out there which sets the correct checked status for all the list entries. (By the way, CheckableViewGroup also overrides on{Save,Restore}InstanceState() but that won't be called regardless whether or not it has an ID assigned (presumably because it never gets attached to the layout root?).
So it looks as if the ListView at the same time knows and does not know its getCheckedItemPosition()? Or am I on the wrong track?
public final class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
itemList = (ListView)findViewById(R.id.ma_list);
listAdapter = new MyAdapter();
itemList.setAdapter(listAdapter);
itemList.setOnItemClickListener(
new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> av, View v, int pos, long id) { checkForm(); }
}
);
listAdapterSetup();
// this is where itemList.getCheckedItemPosition() returns -1
// when the listView has been re-built from NonConfiguration data:
checkForm();
}
}
I was making another test after I posted my question, because I was getting an idea while describing my observations.
And indeed, my suspicion was confirmed.
Timing is key here.
The ListView will report the correct getCheckedItemPosition() value in onResume() (but not before).
So the solution is easy: Perform any evaluation logic in onResume().

Implementing "Drilldown" navigation in Android App UI

I am trying to learn how to do stuff in Android, and I'm not sure of the best way to build the interface.
I've been working on porting an iPhone app, which uses navigation controllers and table views for looking at the different sections: basically, someone touches a cell in the table, which drills down to another table. when they touch a cell on that table it drills down to a webview that displays the information.
I want to do something similar for the android app, but I don't know how, or if there is a better way native to Android. I've figured out how to use the webview to my purposes, but moving forward and backward in the table tree is unclear.
So on an iphone when you say drill down I guess you mean when a user touches-up on a list row and it slides a new view on from the right, most of the time it has a nav bar at the top to give the user the option to go back?
The way android handles this is simply by starting a new activity. So you would have your 'Books' ListActivity when a listItem is clicked you would define a new intent that starts your 'Chapters' ListActivity and so on. The nav bar at the top of an iphone is not standard UI in android as most people see the dedicated 'back' key as a way of getting back to the previews screen.
This is how you start an intent in case you haven't seen it before:
Intent chaptersIntent = new Intent(this, Chapters.class);
this.startActivity(chaptersIntent);
This article is worth a quick read through as it explains Activities perfectly
http://d.android.com/guide/topics/fundamentals.html
Also have a look at the android version of TableView - ListView:
http://d.android.com/reference/android/widget/ListView.html
and ListActivity:
http://d.android.com/reference/android/app/ListActivity.html
EDIT:: Sample Code
I would do it something like this
public class Books extends ListActivity {
private String[] mBooks = new String[]{ "Book1", "Book2", "Book3", "Book4" };
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ArrayAdapter<String> booksAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
android.R.id.text1,
mBooks);
this.setListAdapter(booksAdapter);
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Intent mViewChaptersIntent = new Intent(this, Chapters.class);
mViewChaptersIntent.putExtra("BookName", mBooks[position]);
startActivity(mViewChaptersIntent);
}
}
So you pass through the id of the book as an extra to the Intent then in your Chapters Activity you get that extra in the onCreate method:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Bundle extras = getIntent().getExtras();
if(extras != null) {
String bookId = extras.getString("BookName");
}
}
Finally make sure all new activities are added to your AndroidManifest.xml file:
<activity android:name=".YourClassName"
android:label="#string/activity_name"
>
</activity>
Hope that helps
The primary way that the Android ui is created is using xml. I'm not exactly sure what you mean when you say drill down but if you want it to change views its as simple as making one set of xml elements visible and another set not. Check out the developer pages for more help.
http://developer.android.com/guide/topics/ui/index.html
Forgot to mention this is also a very good beginner resource.
http://mobiforge.com/designing/story/understanding-user-interface-android-part-1-layouts
As already pointed out XML way of doing layouts is most preferred.
basically, someone touches a cell in
the table, which drills down to
another table. when they touch a cell
on that table it drills down to a
webview that displays the information.
From what I understood from the term drills down, this may be wat you need
http://developer.android.com/guide/topics/ui/ui-events.html
From official docs
An event listener is an interface in
the View class that contains a single
callback method. These methods will be
called by the Android framework when
the View to which the listener has
been registered is triggered by user
interaction with the item in the UI.

Categories

Resources