Android how to get an ancestor view from a child view? - android

I have a list of type Foo with a custom array Adapter. I want to be able to click on a child element in one of the views in the array adapter and get back the view I clicked on of type Foo.
This is how I am clicking on a child element:
// fill array with a test set of objects
final ArrayList<Foo> locations = Foo.getTestingList();
final myCustomArrayAdapter adapter = new myCustomArrayAdapter(rootView.getContext(), myarrayList);
adapter.setDefaultRequestBtnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
//if child element is clicked
if(v.getId() == R.id.deleteBTN){
//tag is set to the position in my custom adapter
int pos = (Integer)v.getTag();
//Get this child's parent view (type foo)
}
}
});
I want to be able to use certain Foo methods on the Fooparent of the child View I just clicked on.

If you wanna get the direct parent of a view, you can call the method getParent() and it will return immediate parent of the target view. Note, this method doesn't directly return a view but instead a ViewParent. ViewParent does not technically need to be a View but all views capable of holding child views i.e. a "view parent" in the Android SDK are of type ViewGroup which itself implements the ViewParent. So in reality virtually all ViewParents are a ViewGroup, which in itself is a View.
Furthermore, if you wanna access an ancestor view that's beyond the direct parent, you can recursively call getParent() and perform checks on the return parent view to determine if they are the desired view.

Related

Custom animation for ExpandableListView Child

I wanna use a custom animation (slide down/up) for childs in an ExpandableListView. So if I click on element #2, I want the child of parent element #2 to expand using the animation. And withdraw / close, when I click the parent again.
However, I do have problems directing the animation at the child itself. The closest I can get, is to animate the parent, by using "myListView.getChildAt(groupPosition).setAnimation(slide_down);" as seen below.
When I use this pierce of code and I click element x, then element x will makes an animation - But it's the child who should make the animation, not the clicked parent.
My code in MainActivity, where "myAdapter" is the adapter and "myListView" is the ExpandableListView:
ExpandableListAdapter myAdapter = new ExpandableListAdapter(context, arrRO);
final ExpandableListView myListView = (ExpandableListView) findViewById(R.id.reminderlistView);
myListView.setAdapter(myAdapter);
myListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
if (myListView.isGroupExpanded(groupPosition)) {
//Need to implement collapsing animation as well
myListView.collapseGroup(groupPosition);
} else {
boolean autoScrollToExpandedGroup = false;
myListView.expandGroup(groupPosition, autoScrollToExpandedGroup);
setupLayoutAnimation(groupPosition);
//
}
//telling the listView we have handled the group click, and don't want the default actions.
return true;
}
private void setupLayoutAnimation(int groupPosition) {
Animation slide_down = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_down);
myListView.getChildAt(groupPosition).setAnimation(slide_down);
//myListView.setAnimation(slide_down);
}
I also included the "myListView.setAnimation(slide_down);", but if I use that and click on an element, every single displayed element (parents + children) make this little animation, and I only want it for the child.
There will always only be 1 child, for every parent, if that makes any difference.
ExpandableListView is not very flexible. You are probably better off creating a custom view where you can control how the children of a group are displayed when the group is clicked.
There is a bit more work to get your custom view in place, but it'll aford you much more flexibility that an ExpandableListView can.
You'll need 2 new views, a Parent view, and a child view. The Parent view will inherit from one of the ViewGroups (use LinearLayout or FrameLayout as you have a single child), while the childView will be based on what you want to display, it could be a TextView or some ViewGroup with a few child views. When you detect a click on the Parent, you would animate the child it contains, and you could pass that click event up the chain using an interface if needed.

Get access to particular item's layout in list view

In my android app my Main Activity extends List Activity. I store there elements called Items, their layout is defined by itemLayout xml file and I use custom adapter (called ItemAdapter) to transfer data to List View in Main Activity. In itemLayout there's an ImageView and my aim is to change its image when user clicks on the particular item in list view. In my opinion the easiest way to achieve that is to get access to particular item's (the one that was clicked) layout, there find the ImageView and call method setImageBitmap. How can I "find" this layout of clicked item? I tried many things in method:
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
}
but nothing worked. Do I have to add anything to my ItemAdapter? Or is it possible to do in onListItemClick(…) but I can't find out how?
You're thinking about it in slightly the wrong way. Adapter's are a way to map data to views. So if you want to change how a particular view looks for a given position, you need to change it's correlating data so that the rendered View then changes. Attempting to modify a view directly kinda goes against how adapters are meant to be used.
So in your case, when a user clicks on an item. Find that item in your adapter via the position number. Then update the item and ensure notifydataset is called. Meanwhile, your adapter's getView() will then handle displaying the appropriate image.
As I understood you need to modify clicked item layout, right? Use argument from onListItemClicked:
v.findViewById(<your_img_view_id>)
For better performance use view holder.
onListItemClick is fired when you press on an element of the ListView. If you want to retrieve the element in the dataset, you can simply invoke
l.getItemAtPosition(position)
the returned value has to be casted to the specific object
Yes It is possible in your custom adapter class in the getView() mtheod u can change imageview bitmap by clicking on it
see this code
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View rowView = convertView;
rowView = inflater.inflate(R.layout.playlist_item, null);
final ImageView im = (ImageView) rowView.findViewById(R.id.favorite);
im.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// Do your stuff here
}
});
return rowView;
}

How to know which child an item is for its parent

I have a multiple choice list view and for its adapter I have designed a layout file. I have an image view in the layout and when it's clicked, I want to know what child of the list it is. I mean the child id for the its parent which is the list to further use the method list.getChildAt(???). can anyone tell me how to get that?
The image is independent of the list view and for its onClick attribute I've written a different method that changes image view resource... How can I know which child that a particular imageView is when I click on it?
In the XML layout I have this:
<ImageView
android:id="#+id/choice_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="deleteSelected" />
And here is a part of deleteSelected method:
public void deleteSelected(View view) {
icon = (ImageView)view.findViewById(R.id.choice_image);
list.getChildAt(???); \\ To know which child the view is
}
I have set the adapter as follows:
list.setAdapter(new ArrayAdapter<String>(this, R.layout.list_choice_multiple,
R.id.choice_text, terms) {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
icon = (ImageView)v.findViewById(R.id.choice_image);
icon.setImageResource(R.drawable.delete_off);
icon.setTag(R.drawable.delete_off);
return v;
}
});
How can I set the id for each image view so I can access it by getID() method within deleteSelected()?
ListView has a getFirstVisiblePosition method, using that you can calculate the child position based on its position in the list view (which is a parameter passed in to the onItemClicked method of the listener).
int childIndex = listView.getFirstVisiblePosition() - position;
If you're clicking on a child of the row view (View used in the ListView, created by the adapter), then you need to know which position the row belongs too - simplest way is to store the position in the tag of the child when you set the onClickListener
Simple answer: You are writing that the click happens on the ImageView. The ImageView is not associated with the ListView.
So there is no relationship between your click or any element in the ListView.
When clicking on the ImageView, though, the onClick receives a reference to the ListView itself. So what you are trying to achieve? Please be more precise.
Basically first you will have to set an onClickListener for your list-item's ImageView in getView() of the Adaptor.
Now with onClickListener you get the view that is clicked as function parameter to onClick(). Set a different background for this view (ImageView) object.
Hope this is clear. Let me know.

How do I get root view of list_view_item.xml inside ListView adapter?

I have a ListView items/cell that has a few layers, relative, linearLayout etc.
I tried doing v.getParent() inside the onClick of the button but it just went one layer up. How can I get a reference to the root of the current element inside onClick event handler?
Here is my getView()
Button v = (Button)findViewById(R.id.myButton);
v.setOnClickListener(new OnClickListener(){
onClick(View v) {
//Right here I want to find another view inside the cell.
View otherView = ???.findViewById(R.id.myOtherViewInListItem);
otherView.setBackgroundColor(...);
.........................................
}
});
I'm imagining that this button is inside the ListView element. Based on this assumption:
create only one OnClickListener. The way you're doing you're creating adapter.getCount() OnClick listener and waste memory like crazy.
Maybe you want to completely remove the button and use the OnItemClick to track clicks on your whole ListView element, this will pass to you the reference to the whole View.
If you really must have the button, inside your getView you store a reference to the parent, something like that:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// do whatever you're doing to get the view, let's call it v
Button b = (Button)v.findViewById(/* your button id */ )
b.setTag(v)
}
then on your click listener you can:
onClic(View v){
View parent = (View)b.getTag();
}
and if that answer works for you (I know it does) accept it as correct like Daniel Martinus pointed out.
Inside onClick(View v)
just call v.getViewParent(); then you will have a view from which you can call the find for the others.

Android Listview: getView being called multiple times on unobservable views

(I have already seen this similar question)
I have a ListView for which I've written a custom adapter, and an onitemclicklistener. I'm having an issue where, when any element of the list is selected, getView is called (twice) for each of the top 4 elements of the ListView, even if those elements are not visible. This happens even if I don't call notifyDataSetChanged on the adapter - those first 4 views are fetched twice regardless. Is this normal behavior? My issue is not as much that it's being called twice for them, but that it is being called at all when updating them is not needed.
By the way, I am not using wrap_content for the height or width of the listview - the height is match_parent and the width is a fixed number of dp.
The onItemClick() method of the OnItemClickListener is here:
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
mPicture = pictures[position];
mPicturesAdapter.setCurrentPicture(mPicture);
mPicturesAdapter.notifyDataSetChanged();
}
getView() from my custom Adapter (which extends BaseAdapter) is here:
public View getView(int position, View convertView, ViewGroup parent) {
Log.v("tag", "Getting view for position "+position);
LayoutInflater inflater = LayoutInflater.from(mContext);
LinearLayout layout = (LinearLayout)
inflater.inflate(R.layout.picture_thumbnail, parent, false);
// set up the linearlayout here ...
return layout;
}
On any item click, getView() is called for positions 0 - 3 twice regardless of which item was clicked.
Just by modifying the adapter via
mPicturesAdapter.setCurrentPicture(mPicture);
the ListView already tries to update itself. I'm guessing the onClick method will still do it's job without you calling notifyDataSetChanged
Actually whatever List/Group you are using to populate the ListView, you need to first empty it and then recall it. For example, if you use ListA to populate the ListView, in the second or any consecutive update you need to empty the ListA first and then add items and then populate using it.
if (convertView != null){
Then populate list
}

Categories

Resources