Android custom ArrayAdapter | Change icon on ImageView click - android

I have a list with elements that use a custom layout which consists of a text view and an image view. For this, I follow ViewHolder pattern like explained here. The image views display one of two icons and I want to change the icon of the clicked image view.
So my first approach was to define the on click listener of the ImageViews in the overridden getView function of my adapter class. The problem is that when the icon of the first ImageView changes and I scroll down to the last its icon changed as well. This question here was not helpful.
Here I found that it's not the best way to handle the click in the getView function but it's better to do it in the listView.setOnItemClickListener. I tried it but I am not able to find out whether an ImageView was clicked or not as the parent object holds the list item and the view parameter the LinearLayout in which the ImageView is contained (even when I click directly in the ImageView). Setting android:focusable="false" of the outer LinearLayout as it is suggested here did not help.
I'm sure someone must have had this issue / use case but I'm not able to find a solution. So, what's the best way to handle the click of the ImageView in my custon list item view?

Try adding the following attributes to the clickable ImageView instead of its ViewGroup, your LinearLayout:
android:focusable="false"
android:focusableInTouchMode="false"
... and as far as updating UI in a AdapterView/ListView/RecyclerView goes, you should make good use of an int flag that tracks the position of the list item that was clicked, and then set it as a conditional statement in getView() before invoking notifyDataSetChanged(), since "every other" row will be updated, especially in lists of say, 100 rows.
I actually answered this in a similar question here and here.

If you have two icons, you can simply put a custom checkbox instead of an imageview :
<CheckBox
android:id="#+id/customchechecbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/checkbox_selector"
android:button="#android:color/transparent" />
checkbox_selector :
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="#drawable/checkbox"
android:state_checked="false"/>
<item android:drawable="#drawable/checkboxselected"
android:state_checked="true"/>
<item android:drawable="#drawable/checkbox"/>
</selector>

Related

How to make each row of android listview a trapezium instead of ractangle?

I want to customize my listview to achieve this design,are there any library available for this?what can be best way to achieve this.Are there any disadvantage with such designs.
Thanks,
You can achieve this in two different ways
add an image instead of divider containing these tilt lines you can do this by using a simple line of code in your layout or in your class
android:divider="#drawable/divider_image"
or you can change it in you java class like this
list.setDivider(R.drawable.divider_image);
the second way of achieving this is you set a static image in you item layout below the item and change it according to your need as if the item is odd set a different image and if the item is even set a different image
<ImageView
android:id="#+id/imageViewDivider"
android:src="#drawable/divider_image"
android:scaleType="fitXY" />
and change the image in java class
ImageView imageView = (ImageView) findViewById(R.id.imageViewDivider);
imageView.setImageResource(R.drawable.divider_image);

Android listview item background change

i have a android listview. i want to change listview item background when i click one listview item.
and then previous selected item must go back to default background. this means only one item has to be selected.
i have searched it for a long time. i can change background of selected item using onItemClick()
but i can't change previous selected item. for example, if i select second item, it was changed. and then i select third item. oh my god! it is changed too! what can i do for this. how can i get the previous position?
here is my android code.
private class ListViewItemClickListener implements
AdapterView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
TextView title = (TextView) view.findViewById(R.id.title);
title.setBackgroundResource(R.drawable.list_shape);
}
}
You should use the built in methods of selecting items in a listview. Manually changing the background is prone to error as you have found.
Add this attribute to the root view in your listview item xml
android:background="?android:attr/activatedBackgroundIndicator"
then call setItemChecked(x, true) on your ListView where x is the position of the item you want to be selected.
Ensure your listview has a ChoiceMode set that allows selection (such as "SingleChoice")
When I have this in a similar example I have a global field named:
selectedListItem;
This would be updated in your onitemClickListener and the previous item would then have it's background returned to the default.
So to update your code:
private class ListViewItemClickListener implements
AdapterView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
//First update the previously selected item if one has been set
if(selectedListItem!=null){
TextView previousTitle = (TextView) selectedListItem.findViewById(R.id.title);
previousTitle.setBackgroundResource(R.drawable.list_default_background);
}
//Then update the new one
TextView title = (TextView) view.findViewById(R.id.title);
title.setBackgroundResource(R.drawable.list_shape);
selectedListItem = view;
}
}
So simply initalise selectedListItem as a field in your adapter with the onClickListener as an inner class and have your default background drawable instead of list_default_background .
Alternatively you can track the position numbers instead of the actual view.
EDIT:
To use this method for your list you will also have to keep track of an ID or object instance for your specific list item. In my own solution, in my ListAdapter's getView method I make sure only the list item that matches the ID/instance of the correct item is updated. With your code the way it is you will also find that when you scroll down the view at the same position in this list of visible items is also updated. This is because list view's refer to the list in sets of items, where each set corresponds to the items visible on the screen at any one time.
To update a singular, specific item you would be better suited to using a selector background or indicator as mentioned in the other answers.
HTH
You can change the ListView item colour on clicking it like below. Follow these steps.
(Remember, This is for Custom List View)
Create an XML file in Drawable Folder as Below:
<item android:drawable="#color/orange" android:state_focused="true"/>
<item android:drawable="#color/orange" android:state_pressed="true"/>
<item android:drawable="#drawable/listview"></item>
Choose your own resources.
While implementing Custom ListVIew, you'll have additional layout for Custom List Item design. Below is such an Example.
<ImageView
android:id="#+id/imageView1"
android:layout_width="60dp"
android:layout_height="60dp" />
<TextView
android:id="#+id/textView1"
android:layout_width="fill_parent"
android:layout_height="60dp"
android:layout_toRightOf="#+id/imageView1"
android:background="#drawable/listselect_picture"
android:gravity="center"
android:text="TextView"
android:textColor="#drawable/select_txtcolor"
android:textSize="16sp" />
In Above code I have put the set the XML file from Step 1 as "background" attribute. This will work as you want to.
Additionally if you want to change the text colour on ListItem selection as well, use below XML code and set that XML file as "TextColor" attribute.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:color="#android:color/white"/>
<item android:state_focused="true" android:color="#android:color/white"/>
<item android:state_pressed="true" android:color="#android:color/white"/>
<item android:color="#android:color/black"/>
</selector>
The code above will change the text color to while on selection and revert to original when unclicked.

Empty space between listview header and first item

I've created an android application with a ListView. I've added both a header and footer to the list. But when adding a divider/separator it also creates an empty space between the header and the first ListView item. It does the same for the last ListView item and the footer.
The empty space is equivalent to the size of the divider between all the ListView items, with the difference that it doesn't draw the divider and just leaves empty space. I thought I found the solution with the xml attributes 'Footer dividers enabled' and 'Header dividers enabled'. But when setting them to false, it doesn't change anything. I even tried to set them programmatically with
list.setFooterDividerEnabled(false);
list.setHeaderDividerEnabled(false);
But it just doesn't work. Any way to fix that problem? I just don't want the empty space to be there, I want the first item to fit exactly to the header (same for the footer).
I stumbled upon the same problem, but in a slightly different situation than yours. My ListView has a header (a search box), but the first item below it contains a section header (a date, or a letter) rather than being a regular list item (with the actual content in form of an image, some text, and so on). As such, I want it not to be selectable, so in my custom adapter I have overridden areAllItemsEnabled to return false.
Big mistake, because that's exactly the culprit. See, it appears that, by design, the ListView implementation only draw dividers between two enabled items, but still reserve space for dividers between an enabled item and a disabled one even if those dividers will not be drawn. The fact this is a conscious design decision does not mean it's not stupid, of course. Most weird of all, this dividers drawing policy is based just on the value returned by areAllItemsEnabled instead of the values returned by single calls to isEnabled for subsequent items.
Thus, to work around it, I just had to return true from areAllItemsEnabled (I kept the overridden method and add a comment about this issue, otherwise I would not be able to remember it a month from now): lo and behold, white space disappeared, replaced by a divider. Now, if I want to show the ListView header and the first section header as being exactly adjacent, I just have to choose a divider color that's the same as the section header color.
Really hope that's the same case as yours, or that my solution helps you in some other way.
I tried a solution by 幻影浪子 that works (based on android-pulltorefresh):
View Layout (header.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<RelativeLayout
android:id="#+id/content"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ProgressBar
style="#android:style/Widget.ProgressBar.Small.Inverse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_margin="16dp"
android:layout_marginTop="2dp" />
</RelativeLayout>
</LinearLayout>
Inflating View:
m_headerView = inflater.inflate(R.layout.header, this, false);
Displaying View:
m_headerView.setPadding(0, 0, 0, 0);
m_headerView.setVisibility(View.VISIBLE);
Hiding View:
m_headerView.setPadding(0, -1000, 0, 0);
m_headerView.setVisibility(View.GONE);
It worked perfectly in our project. I hope it is helpful.
In getview method you can check if the item is first or last and set custom devider which will be of 0 height or single pixel height of transparent color.
goto the ListView properties in android layout and search for spacing tag... some how in android, when creating new layouts, it will defaults creation is spacing header spacing and border properties. check it , if it is available then remove it
Didn't find a great solution.
Set dividerHeight="0dp" and created my own dividers manually - either directly in the layout XML or dynamically in the adapter if you need more precise control.
Just do
list.setDividerHeight(0)
That should take care of it.

Android Gridview and getChildAt with NullPointerException

I have a UI that consists of a Gridview loaded with a custom adapter. A ButtonAdapter, in this case. So the grid loads fine, the button clicks function like I want them to, but now I have to indicate on the button that it the "active" selection.
I thought I'd do this by just keeping track and changing the background. As it turns out, and based on a couple posts here on SO, the buttons don't actually exist when they are off screen...and even immediately after a scroll. I'll often get a NullPointerException when trying to change a button background after scrolling.
I've tried changing the views in the adapter to RadioButtons and ToggleButtons, but they all offer similar limitations.
The problem seems mostly to do with the getChildAt() that I use on the grid to "unselect" one button, or whatever, when another one is selected.
Is there a workaround for this, or perhaps another suggestion of similar functionality. A vertically scrollable, grid-like format, etc...
Thanks for the help.
EDIT:
Thanks Craigy...I did forget to put a platform on there o.0...i'll add android.
Have you considered using a Selector? In ignorance of how your buttonAdapter works or what you're pulling it from, you can set the background drawable of any View to change according to its state using selectors.
If your selector is defined like so (assuming the presence of appropriate drawables, of course):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_focused="true"
android:drawable="#drawable/list_item_pressed" />
<item android:state_pressed="true"
android:drawable="#drawable/list_item_pressed" />
<item android:state_selected="true"
android:state_activated="true"
android:drawable="#drawable/list_item_selected" />
<item android:state_activated="true"
android:drawable="#drawable/list_item_selected" />
<item android:state_selected="true"
android:drawable="#android:color/black" />
<item android:drawable="#android:color/transparent" />
</selector>
And then set your GridView's choice mode to single Choice:
<GridView
...
android:choiceMode="singleChoice" />
This lets the OS take care of everything for you in terms of remembering which position is selected in the list and then clearing it out for you when you've clicked another one
Set a tag on each of the views that the adapter creates in getView(). Later search for the view with that tag by gridView.findViewByTag() or get the view's tag by view.getTag().
Well, this may not perfectly answer your question but I had done something sort of similar. Basically, I added items to a table and needed to have a remove button associated with the item. When the remove button was clicked, it needed to remove only that item from the table. This could be adapted to your needs so rather than removing the item clicked, it finds the previous item, unclicks it, and then highlights then newly clicked one.
So what I did was give a tag to the buttons themselves (obviously they need to be unique). When a button is clicked, save its tag in something like a sharedPreference for later reference. Then when a new button is clicked, simply find the button with the previously clicked tag and unmark the row that it is in and then mark the row for the newly clicked button. Here is the code I used (sorry the variable names are terrible, I actually had this working in a test app that was never released so I didn't bother giving them better names):
//Previous button clicked
String id = <get this from wherever you choose to store it>
// create a new TableRow
TableRow row = new TableRow(getApplicationContext());
TextView t = new TextView(getApplicationContext());
t.setTextColor(Color.BLACK);
t.setText(unique);
Button b = new Button(getApplicationContext());
b.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v)
{
for(int i = 0; i < table.getChildCount(); i++)
{
TableRow row = (TableRow) table.getChildAt(i);
Button bt = (Button) row.getChildAt(1);
TextView view = (TextView)row.getChildAt(0);
if( id.equals(v.getTag())) //they match, so this is the button that was previously clicked
{
//Put your code here to unclick the previous button and mark the new one as clicked.
}
}
}
});
b.setText(R.string.removeButtonText);
b.setTag(t.getText().toString());
/***BE SURE TO SAVE THE NEW BUTTON TAG (t.getText().toString()) SOMEWHERE LIKE A SHARED PREFERENCE****/
//saving the tag
//add the row to the table
row.addView(t);
row.addView(b);
// add the TableRow to the TableLayout
table.addView(row,new TableLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
Again, I don't suspect this is the exact answer you are looking for, but maybe it will give you an idea to try out. Hopefully this makes some sense, if not please feel free to ask for clarification. Sorry if it is way off base as well.

Android listview change image in row

Hello i'm working on an app where i'm basically just making a custom multi select listview i did something like this LeftAL is just an array list and this code below is in my onClick
if(LeftAL.contains(position)){
ImageView imageView = (ImageView) lView.getChildAt(position).findViewById(R.id.checkbox);
imageView.setImageResource(R.drawable.checkboxoff);
int i = position;
Integer intObj = new Integer(i);
LeftAL.remove(intObj);
}else{
ImageView imageView = (ImageView) lView.getChildAt(position).findViewById(R.id.checkbox);
imageView.setImageResource(R.drawable.checkbox);
LeftAL.add(position);
}
and then checkboxoff looks like this
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="#drawable/checkbox_pressed_off" />
<item android:drawable="#drawable/checkbox_off" />
</selector>
and checkbox on is the same thing basically just different images
Now that all works fine as it should and i didn't actually notice this for a little while but when i check say item 3 in my list. It checks and adds to the array list as it should however if i scroll down to the next group of list items i will see that number 3 of the second set is also checked for instance lets just say for example only 3 rows show on my phone.
Cat
Dog
Egg
-------off screen-----
Fox
Gerbil
Hog
I check Dog then i scroll gerbil would also be checked i guess this is just android like recycling or something but it's definately an issue how can i fix this so that only 3 in the list checks not 3 in the next set as well.
Thank you for any help
Android absolutely recycles the Views in a ListView. What you need to do is ensure that you are storing the checked / unchecked state in a separate list and set the state of the check box accordingly each time it's shown.

Categories

Resources