How to find element inside a gridview in Android? - android

I have a grid view which I populate using a custom adapter.
While populating the gridview I give each element inside a unique tag.
Once this gridview is populated, I wish to find a specific element inside the gridview with its tag. How do I find this?
Currently I'm doing this:
gridviewobject.findViewById(thetag);
// gridview object is the object of the gridview that i have populated.

What you have written above will work, except be aware that a) searching for a view by its tag is probably the slowest method you could use to find a view and b) if you try requesting a view with a tag and that view is not currently visible, then you will get null.
This is because GridView recycles its views, so essentially it only ever makes enough views to fit on screen, and then just changes the positions and content of these as you scroll about.
Possibly a better way might be to do
final int numVisibleChildren = gridView.getChildCount();
final int firstVisiblePosition = gridView.getFirstVisiblePosition();
for ( int i = 0; i < numVisibleChildren; i++ ) {
int positionOfView = firstVisiblePosition + i;
if (positionOfView == positionIamLookingFor) {
View view = gridView.getChildAt(i);
}
}
Essentially findViewWithTag does something similar, but rather than comparing integers it compares the tags (which is slower since they're objects and not ints)

Related

Android RecyclerView getChildAt() and getChildAdapterPosition()

I saw a sample code and couldn't understand the meaning of the following method:
public int getAdapterPositionForIndex(RecyclerView parent, int index) {
final View child = parent.getChildAt(index);
return parent.getChildAdapterPosition(child);
}
My understanding is what's returned should always equal to index, but my debugger obviously doesn't say so. Since the docs are not explaining well the difference between getChildAt() and getChildAdapterPostion(), I hope I could get some expert insights here.
Well as per my understanding getChildAt() is a method of ViewGroup . And it does Returns the view at the specified position in the group.
Since RecyclerView is an AdapterView i.e items get recycle when goes out of boundary it returns null for #getChildAt().
I am not sure whats the exact reason may be some should explain this
On other hand #getChildAdapterPosition() Return the adapter position that the given child view added to.
Look at the code below :(Only adding the essential)
findViewById(R.id.b1).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LinearLayoutManager layoutManager= (LinearLayoutManager) rvNumber.getLayoutManager();
final View child = layoutManager.findViewByPosition(30);
if(child!=null) {
int i = rvNumber.getChildAdapterPosition(child);
Log.i("pos", i + "");
}else{
Log.i("pos", "View is null");
}
}
});
Nothing complex here! I laid down 60 items in RecyclerView just a TextView. In which 10 items are showing at a time in list . So the first time 10 views will be laid down (0-9).
When i call the above code on clicking on button it gives me a null view . Cause Views is not inflated yet for position 30. But after scrolling to position 30 it returns the view and hence its position by getChildAdapterPosition() which will be 30 also .
I think you should make a sample and play around with it for better understanding.
FROM DOCS
getChildAdapterPosition()
Return the adapter position that the given child view corresponds to.
getChildAt()
Returns the view at the specified position in the group.
The Difference
It Means the getChildAdapterPosition() method return the the position of View inside recyclerview adapter
AND
the getChildAt() method returns the View from a viewGroup of specific position
In short
The Both method are different getChildAt() is retuning view from a viewGroup while the other getChildAdapterPosition() retuning the postion of a view in recyclerview adapter

How to hide a column in a Gridview (android)

I've got a GridView (Android). I would like to hide one of it's columns and then access to it's values.
Is it possible?
Update: based on your reply, I think it best you hold your data in a map, rather than using an invisible column...
Example:
HashMap<Integer, Integer> map_positionToId = new HashMap<Integer, Integer>();
map_positionToId.put(position, id);
int id = map_positionToId.get(position);
There is no easy setting to flip on gridview to make a column invisible that I am aware of.
However, below is a suggestion to try... It may take a bit of trial and error to pull off correctly:
This is the getView method for your gridView adapter:
public View getView(int position, View convertView, ViewGroup parent) {
//You want your if(convertView == null) code here.
//As we can't set visibility of a null object;
....
// Assuming u want to blank the 3rd column, in a 3 column gridview
if(position % 3 == 0)
convertView.setVisibility(View.INVISIBLE); //u can try gone too?
else
convertView.setVisibility(View.VISIBLE);
// rest of your code...
}
You might also play around with padding / margins, and view width, to get the desired effect if you are trying to push the invisible column off the screen.

GridView get view by position, first child view different

Android GridView is quite interesting, it reuses the child views. The ones scrolled up comes back from bottom. So there is no method from GridView to get the child view by its position. But I really need to get view by its position and do some work on it. So to do that, I created an SparseArray and put views by their position in it from getView of BaseAdapter.
SparseArray<View> ViewArray = new SparseArray<View>();
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null)
view = li.inflate(layoutID, null);
ViewArray.put(position, view);
}
Now, I can get all visible views by their position. Everything works perfect as it should but in some devices, the first child view(position 0) is not same as the one in array. I logged the getView and found that for position 0, getView got called many times and each time array was set with different view. I have no idea why GridView is calling getView for position 0 many times and that happens only on few devices. Any solution ?
After reading source of getPositionForView, I have wrote this method in own GridView, works perfect by API 18
public View GetViewByPosition(int position) {
int firstPosition = this.getFirstVisiblePosition();
int lastPosition = this.getLastVisiblePosition();
if ((position < firstPosition) || (position > lastPosition))
return null;
return this.getChildAt(position - firstPosition);
}
You can't reach the views directly because of the recycling. The view at position 0 may be re-used for the position 10, so you can't be sure of the data present in a specific view.
The way to go is to use the underlying data. If you need to modify data at position 10, then do it in the List or array under your adapter and call notifyDataSetChanged() on the adapter.
if you need to have different views for different data subtypes, you can override the two following method in your adapter: getItemViewType() and getViewTypeCount()
Then, in getView() you can 1) decide which layout to inflate 2) know the type of view recycled using getItemViewType()
You can find an example here:
https://stackoverflow.com/a/5301093/990616
There was an issue reported for this. Here is the link. This issue has been closed as WorkingAsIntended. Wish means we can expect the GridView to call getView() on pos 0 multiple times.
My work around is as follow:
public class GridAdapter extends BaseAdapter {
...
int previouslyDisplayedPosition = -1;
...
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(previouslyDisplayedPosition != position) {
....
previouslyDisplayedPosition = position;
}
return convertedView;
}
What I am trying to do here is returning the same 'convertView' if same pos is called again and again. There by preventing any logic within getView() (eg setting image view etc)to be executed again and again.

How to get Position of an view added dynamically on LinearLayout

I need to get an dynamically added view position in LinearLayout with vertical orientation.
For example i have 4 TextViews added dynamically on LinearLayout, then i need to change position of text colour at 3rd position will be in different color.How can i achieve it by getting position of added views.
You can do it just like that
ViewGroup parent;
int position;
for(int i = 0; i < parent.getChildCount(); ++i) {
int currentViewId = parent.getChildAt(i).getId();
if(currentViewId == wantendViewId) {
position = i;
}
}
That's (in my opinion) the simplest way
If you always know the number of TextViews in your LinearLayout, you can just use the function getChildAt( int position ). This returns a View which you can then cast to a TextView to be able to perform the desired operations.
If you do not know the number of elements you could set the id of each TextView (in order to be able to identify a particular one) and then run through them like this:
for( View view : myLinearLayout )
if( view instanceof TextView && view.getId().equals( idToSearchFor ) )
//Do what needs to be done.
I see following options:
Declare some id's in resources in form of <item type="id">first</item> and assign them to
views in adding to layout, after that use normal findViewById() mechanism
Assign some tags to views you're adding to a layout via setTag method and after that use findViewWithTag mechanism
Remeber position of your views and use them vie getChildAt method
I got simple option.
suppose you add
View v;//any view
linearlayout.addview(v);//add in layout
While u want to modify view.
simpaly remove old view.
linearlayout.removeView(v);
add new update view object
v-updated new view
linearlayout.addview(v);

Android: Access child views from a ListView

I need to find out the pixel position of one element in a list that's been displayed using a ListView. It seems like I should get one of the TextView's and then use getTop(), but I can't figure out how to get a child view of a ListView.
Update: The children of the ViewGroup do not correspond 1-to-1 with the items in the list, for a ListView. Instead, the ViewGroup's children correspond to only those views that are visible right now. So getChildAt() operates on an index that's internal to the ViewGroup and doesn't necessarily have anything to do with the position in the list that the ListView uses.
See: Android ListView: get data index of visible item
and combine with part of Feet's answer above, can give you something like:
int wantedPosition = 10; // Whatever position you're looking for
int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount(); // This is the same as child #0
int wantedChild = wantedPosition - firstPosition;
// Say, first visible position is 8, you want position 10, wantedChild will now be 2
// So that means your view is child #2 in the ViewGroup:
if (wantedChild < 0 || wantedChild >= listView.getChildCount()) {
Log.w(TAG, "Unable to get view for desired position, because it's not being displayed on screen.");
return;
}
// Could also check if wantedPosition is between listView.getFirstVisiblePosition() and listView.getLastVisiblePosition() instead.
View wantedView = listView.getChildAt(wantedChild);
The benefit is that you aren't iterating over the ListView's children, which could take a performance hit.
This code is easier to use:
View rowView = listView.getChildAt(viewIndex);//The item number in the List View
if(rowView != null)
{
// Your code here
}
A quick search of the docs for the ListView class has turned up getChildCount() and getChildAt() methods inherited from ViewGroup. Can you iterate through them using these? I'm not sure but it's worth a try.
Found it here
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
View v;
int count = parent.getChildCount();
v = parent.getChildAt(position);
parent.requestChildFocus(v, view);
v.setBackground(res.getDrawable(R.drawable.transparent_button));
for (int i = 0; i < count; i++) {
if (i != position) {
v = parent.getChildAt(i);
v.setBackground(res.getDrawable(R.drawable.not_clicked));
}
}
}
});
Basically, create two Drawables - one that is transparent, and another that is the desired color. Request focus at the clicked position (int position as defined) and change the color of the said row. Then walk through the parent ListView, and change all other rows accordingly. This accounts for when a user clicks on the listview multiple times. This is done with a custom layout for each row in the ListView. (Very simple, just create a new layout file with a TextView - do not set focusable or clickable!).
No custom adapter required - use ArrayAdapter
int position = 0;
listview.setItemChecked(position, true);
View wantedView = adapter.getView(position, null, listview);
This assumes you know the position of the element in the ListView :
View element = listView.getListAdapter().getView(position, null, null);
Then you should be able to call getLeft() and getTop() to determine the elements on screen position.

Categories

Resources