I know their are a lot of question relative to refreshing listView, but none of them are anwering my problem (as far as I know).
I'm trying to change my item view when clicking on it in my list view.
To change the view I've got a boolean isClicked on my POJO :
networksListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> _adapter, View view, int pos, long id) {
myApp.networksGlobal.networks.get(pos);
myApp.networksGlobal.networks.get(pos).isClicked = !myApp.networksGlobal.networks.get(pos).isClicked;
adapter.notifyDataSetChanged();
}
});
When I click on the item isClicked switch from true to false, and on my getView listAdapted I'm switching the view type :
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Network network = (Network) getItem(position);
NetworkItemView networkItemView;
if (convertView == null) {
networkItemView = NetworkItemView_.build(context);
} else {
networkItemView = (NetworkItemView) convertView;
}
networkItemView.bind(network);
if (network.isClicked) {
networkItemView.networkItemButtonLayout.setVisibility(View.VISIBLE);
} else {
networkItemView.networkItemButtonLayout.setVisibility(View.GONE);
}
return networkItemView;
}
On the first click everything is working great, the Toast is shown an the Layout networkItemButtonLayout is set to visible.
But if I click a second time on the same item : nothing happend. No Toast is shown and no changes on the Layout visibility.
If I comment adapter.notifyDataSetChanged() the Toast is shown for every click. So I guess the problem is why the call to adapter.notifyDataSetChanged(). So tried several work around (adapter.notifyDataSetChanged() and networksSearchListView.invalidateViews()) but nothing do the trick, and I can't find a way to click several time on my item.
Does I'm using 'notifyDataSetChanged' the proper way ?
Related
Well, I have a horizontal LinearLayout, with items of a custom class.
What I want: Change background color of the item i've clicked (like if it's selected). If user clicks other item, the first one changes again to original color and the new one changes to "selected color"
What is my problem: This works fine when all items of the listView fit in the screen ( in this case 3 items). If there are more items, let's say 7, if user clicks item number 0, it changes color, but if user scrolls to the last item and clicks item number 6, it changes color, but item 0 doesn't change. If both items are visible, it works fine.
this is the code of my onItemClickListener.
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(it.sephiroth.android.library.widget.AdapterView<?> parent, View view, int position, long id) {
for(int i=0;i<listView.getCount();i++){
try{
getViewByPosition(i, listView).setBackgroundResource(R.drawable.skin);
listView.getChildAt(i).setBackgroundResource(R.drawable.skin);
}
catch(Exception e){
System.out.println(e.toString());
}
}
view.setBackgroundResource(R.drawable.skin_selected);
}
});
why not use the adapter for the modification?I presume you are using a custom adapter?
in You Adapter
public int selectedItem;
.
//Rest of the stuff
.
.
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
if (null == convertView) {
LayoutInflater inflater = (LayoutInflater) _context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_item, parent, false);
}
if(selectedItem==position){
convertView.setBackgroundResource(R.drawable.skin_selected);
}else{
convertView.setBackgroundResource(R.drawable.skin);
}
return convertView;
}
and your onclick listener becomes :
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(it.sephiroth.android.library.widget.AdapterView<?> parent, View view, int position, long id) {
((NameOfYouAdpater)listView.getAdapter()).selectedItem=position;
((NameOfYouAdpater)listView.getAdapter()).notifyDataSetChanged();
}
});
And I noticed you are using a custom list view in itself.Maybe look into the implementation of the library to check for interference?
EDIT:the cause of your issue is most probably dude to view recycling.The background colour does not get updated because everytime the list item is outside your ViewPort,the view is recycled.
I have an app that displays a list of articles, which when clicked on changes its background color to green. The ListView is expanded by ViewPager. The color change occurs so that the user knows which articles has been read.
It is also remembered, so that the next time the user loads up the same list, items that have been clicked on remains green. The code below is what I used to make this work. The problem that I am now having is that, when pressing down long enough for the context menu to appear, my articles on ListView no longer changes color upon selection.
Before I instigated the green background change for each item that is clicked on, selecting items in the ListView (context mode) used to get grayed out. The context menu and functionality still works, but it no longer shows which items have been selected. Please can someone advise?
public void onListItemClick(ListView l, View v, int postion, long id) {
Article a = ((toReadListAdapter) getListAdapter()).getItem(postion);
// when item has been clicked on, variable is set to true.
a.setRead(true);
saveToReadList(toReadList);
.....
Custom Adapter:
// Defining custom adapter
private class toReadListAdapter extends ArrayAdapter<Article> {
public toReadListAdapter(ArrayList<Article> listToRead) {
super(getActivity(), 0, listToRead);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = getActivity().getLayoutInflater().inflate(R.layout.new_articlelistfragment, null);
}
Article en = getItem(position);
.....
/*if the article has been clicked on, then read attribute value is true and
background is green*/
if(en.isRead()){
convertView.setBackgroundColor(Color.parseColor("#C8E6C9"));
}else{
convertView.setBackgroundColor((Color.parseColor("#ffffff")));
}
/* convertView.setBackgroundColor(Color.parseColor("#66BB6A"));*/
return convertView;
In the onClickListener() of listView item set
CheckedTextView item = (CheckedTextView)view;
if(item.isChecked()){
convertView.setBackgroundColor(Color.parseColor("#C8E6C9"));
}
Question
I have a listView inside a DialogFragment and I want to fire certain callbacks only when certain particular items inside a row are fired. How can I do that?
Basically, I want to do something like this
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final int viewId = view.getId();
if ((viewId == R.id.textView1) || (viewId == R.id.textView2)) {
// do something...
}
which I can't. Read further if you don't know why.
What I tried
I tried to look into the documentation, but the OnItemClickListener callback doesn't offer as a parameter the exact clicked view (the View you can see in the signature is the whole row).
Also, I tried to set a simple onClick callback on the single view in the adapter, but this overrides the listSelector and other behavior a list should have. Reading in the documentation, I found it's explicitly written that we should set callbacks via the onListItemClick(...) method (not via onClick(...)), so I'm looking for a way to do that, using this method, not to override any default list behavior.
I was trying to get this done by working on the xml. To my surprise, I found that if I set a view android:clickable property to true, the onListItemClick callback won't fire (I thought it was the opposite),
so a partial solution would be to set to android:clickable=true every view in the row apart from the one I want to fire the callback, but that is not a solution because if the user clicks where there is padding or white space, the callback will fire. Also, I found that if I set the parent of the row's view to android:clickable=true and the child views I want to handle with the callback to android:clickable=false, this won't work, because apparently the property is not overwritten.
EDIT Sorry for the really bad title this question had before, I didn't even noticed I submitted the question.
new Answer, hope I understood now :)
In your adapters getView, attach an OnClickListener to any view in your layout you want to fire. (more pseudocode)
public class Adapter extends ArrayAdapter<XYZ> {
private int resource;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null) convertView = ((LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(this.resource, parent, false);
((Button)convertView.findViewById(R.id.YOUR_BUTTON_IN_LAYOUT)).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
DOSTUFF();
}
});
return convertView ;
}
}
old Answer:
The position indicates where you are in the list (pseudocode).
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, final int position,long arg3) {
YOUR_ITEM_BACKED_BY_ADAPTER item = listView.getItemAtPosition(position);
if(item==THE_FIRST_ITEM_IN_LIST) doSomething();
else if(item == THE_LAST_ITEM_IN_LIST) doSomethingElse();
}
});
You can set listeners for other views inside the adapter's getView
public class MyAdapter extends ArrayAdapter<MyItem> implements View.OnClickListener {
public View getView(int position, View convertView, ViewGroup parent) {
// setup the converView inflating it, for simplicity I've removed that code
MyItem item = getItem(position);
text1 = (TextView)convertView.findViewById(R.id.text1);
text2 = (TextView)convertView.findViewById(R.id.text2);
text1.setOnClickListener(this);
// pass the item to use when clicked
text1.setTag(item);
text2.setOnClickListener(this);
text2.setTag(item);
}
public void onClick(View v) {
MyItem item = v.getTag();
switch (v.getId()) {
case R.id.text1:
download(item);
break;
case R.id.text2:
upload(item);
break;
}
}
}
Instead of hardcoding action (eg download) inside the adapter you can pass to it an interface and for example the calling activity can implement that interface
Can someone explain this issue to me ?
I have a listview that holds more rows than the screen can show, so scrolling.
If I click on one item, I replace an icon that is part of each row. That all works.
The issue I have is that when I click on lets say the first item, I change the icon for that first row. When I now scroll down I see that the first row outside the visible viewport also changed the icon.
Why is that happening and how can I avoid this issue ?
Thanks in advance,
Mozzak
Just to make sure, you are using a class that implements ListAdapter or extends some other sort of adapter right?
When using an adapter, you will have to keep in mind that the views in the ListView are recycled to save memory. Because of this, you will need to store the state in a separate variable.
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
{
LayoutInflater inflator = (LayoutInflater)parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflator.inflate(R.layout.listitem, null);
}
// Retreive my image that may or may not change
ImageView myIcon = (ImageView) convertView.findViewById(R.id.iconView);
// Checking my stored boolean for this position to see if I need to use icon2 or icon
if (myItem[position].needsIconChanged)
{
// I have set my boolean, so use icon2
myIcon.setImageResource(R.drawable.icon2);
}
else
{
// I have not set my boolean, or set it to false so set it to icon
myIcon.setImageResource(R.drawable.icon);
}
return convertView;
}
You will also have to remember to set that boolean in your onItemCLick
public void onItemClick(AdapterView<?> myAdapter, View myView, int position, long arg3) {
// Retreive your item and set a boolean or icon state (depending on what you do)
myAdapter.getItemAtPosition(position).needsIconChanged = true;
}
An activity has a Button and a ListView.
Initially, only the Button is visible. When the button is pressed, the ListView is displayed.
When displayed, is it possible for me to show one particular item as selected/focussed?
A use case could be that suppose it is a list of language settings and when the list opens, the currently selected language must be shown as highlighted.
If I know the index of the item, how to set it as focused on display?
I post my solution, because google still doesn't know the answer.
getListView().setItemChecked(selectedGroupIndex, true);
In short, ListView::setSelection(int position) is what you need. However, depending on whether the device is in touch mode or not, it may or may not have visual effect (background highlighting). For more details, refer to Android ListView Selection Problem
If you use an Adapter for your ListView add this code to your adapter:
public class MyAdapter extends ArrayAdapter<MyClass> {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflator = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflator.inflate(R.layout.my_adapter, null);
} else {
rowView = (View) convertView;
}
//...
// set selected item
LinearLayout ActiveItem = (LinearLayout) rowView;
if (position == selectedItem){
ActiveItem.setBackgroundResource(R.drawable.background_dark_blue);
// for focus on it
int top = (ActiveItem == null) ? 0 : ActiveItem.getTop();
((ListView) parent).setSelectionFromTop(position, top);
}
else{
ActiveItem.setBackgroundResource(R.drawable.border02);
}
}
private int selectedItem;
public void setSelectedItem(int position) {
selectedItem = position;
}
}
In your Activity:
myAdapter.setSelectedItem(1);
I am using an Adapter and didn't want to set custom background colors, but use the android:state_selected in drawable xml. SetSelection didn't work for me, but maybe that's also since I needed SetNotifyDataChanged which shows that the Selected State is not persistent.
I also found that the Selected state for an item in a ListView is not persistent, since SetNotifyDataChanged results in updating the ListView layout which clears them all. Setting the item to Selected in the Adapter's GetView is too soon too.
Eventually I set the Selected state for the view of the selected item after the layout of the listview has been changed, which is when LayoutChange event is being triggered (in Java it's probably attaching a to OnLayoutChangeListener of the ListView).
To make it really easy I store the view of the selected item as Adapter's SelectedItemView.
In the ListView's LayoutChange eventhandler I just set the adapter's SelectedItemView.Selected to true.
Here's the code from my Activity where I set the Adapter for the ListView and also subscribe to LayoutChange (or in Java attach an OnLayoutChangeListener)
ringTonesListView.Adapter = ringTonesListAdapter;
ringTonesListView.LayoutChange += (s, layoutChangeArgs) => {
//At this stage the layout has been updated and the Selected can be set to true for the view of the selected item. This will result in android:state_selected logic to be applied as desired and styling can be completely done per layout in Resources.
ringTonesListAdapter.SelectedItemView.Selected = true;
};
Here's my code for the Adapter:
public class RingTonesListAdapter : BaseAdapter<RingToneItem>
{
List<RingTone> Items { get; set; }
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view = convertView;
// re-use an existing view, if one is available
// otherwise create a new one
if (view == null)
{
view = Context.LayoutInflater.Inflate(Resource.Layout.AlertSoundItem, parent, false);
view.Click += SelectRingTone;
}
RingTone ringTone = this[position];
if (ringTone.Selected)
{
//==> Important
//Store this view since it's the view for the Selected Item
SelectedItemView = view;
//Setting view.Selected to true here doesn't help either, since Selected will be cleared after.
}
return view;
}
private void SelectRingTone(object sender, EventArgs args)
{
View view = (View)sender;
string title = view.FindViewById<TextView>(Resource.Id.ringToneTitle).Text;
RingToneItem ringToneItem = Items.First(rt => rt.Title == title);
if (!ringToneItem.Selected)
{
//The RingTone was not selected and is selected now
//Deselect Old and Select new
foreach (RingToneItem oldItem in Items.Where(rt => rt.Selected))
{
oldItem.Selected = false;
}
// Select New RingTone
ringToneItem.Selected = true;
//Update the ListView.
//This will result in removal of Selected state for all Items when the ListView updates it's layout
NotifyDataSetChanged();
}
//Now play the test sound
NotifierService.TestSound(Context, ringToneItem);
}
public View SelectedItemView { get; set; }
}