Like button on every single row of listview - android

Im trying to implement instagram like listview , in each row there is like button and also comment box. the question is how can i achieve similar function in listview which means each row is specific and its not repeating for other rows , what i tries is , when a user clicks on button after some item , all other items are clicked! means the clicked item is repeating and its obvious i don't want this! how can i achieve instagram like row
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
viewHolder mHolder;
if(convertView==null){
mHolder = new viewHolder();
convertView = mInflator.inflate(R.layout.row_all_artist, parent, false);
mHolder.mArtistName = (TextView) convertView.findViewById(R.id.artist_name);
mHolder.mFollowers = (TextView) convertView.findViewById(R.id.artist_followers);
mHolder.mFollow = (Button) convertView.findViewById(R.id.artist_follow);
AppLogic.ChangeTextViewFont(mContext, mHolder.mArtistName);
convertView.setTag(mHolder);
} else{
mHolder = (viewHolder) convertView.getTag();
}
mHolder.mArtistName.setText(mItems.get(position).getArtistFullName());
mHolder.mFollowers.setText(mItems.get(position).getArtistFollowers());
mHolder.mFollow.setTag(R.id.artist_follow,mItems.get(position).getArtistID());
mHolder.mFollow.setOnClickListener((OnClickListener) mContext);
return convertView;
}
EDIT
my question is not about touching items or setting unlike listener or like this! the problem is when i click the button i change its background color , but this color is repeating on every 10 item on the list! there is a related question to me here : ListView repeated CheckBox behavior every 10th item erratically
public void onClick(final View v) {
if (!AppLogic.isLoggined(mShared)) {
AppLogic.ToastMaker(getApplicationContext(),
getResources().getString(R.string.msg_loginError));
startActivity(new Intent(FirstTimePage.this, Register.class)
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
} else {
AppLogic.doFollow(FirstTimePage.this, v, mShared);
}
}

Prevent getting focus by the button.
Add this to the top element in your row_all_artist.xml custom view
android:descendantFocusability="blocksDescendants"

Create a new OnClickListener for every row, or check the View given in the argument at your current listener.

You are setting your mContext as the OnClickListener
mHolder.mFollow.setOnClickListener((OnClickListener) mContext);
You should just implement the ListView method setOnItemClickListener and then check for the position of the item that was clicked. Tags are also very helpful here.
Example: Adding an onclicklistener to listview (android)

Related

Android ListView actions repeat in different items

I have a custom layout for a Listview, each row item contains a button that when clicked it shows a small imageview in the item, however the actions i perform in one item, repeats for another item down the list, for example, if i click the button in item 1, the imageview will show up in item 1 and item 10, if i click the button in item 2, the Imageview will show up on item 2 and item 11 and while i scroll it will keep repeating in different items, heres the code for my custom adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
mparent = parent;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.places_item, parent, false);
holder = new ViewHolder();
holder.placeimage = (CircularImageView) convertView.findViewById(R.id.locationimage_pilayout);
holder.addbtn = (TextView) convertView.findViewById(R.id.addbtn_pilayout);
holder.delbtn = (TextView) convertView.findViewById(R.id.delbtn_pilayout);
holder.oribtn = (TextView) convertView.findViewById(R.id.oribtn_pilayout);
holder.placename = (TextView) convertView.findViewById(R.id.locationname_pilayout);
holder.selected = (ImageView) convertView.findViewById(R.id.selected_pilayout);
holder.origin = (ImageView) convertView.findViewById(R.id.origin_pilayout);
holder.swipeLayout = (SwipeRevealLayout) convertView.findViewById(R.id.swipe_pilayout);
holder.mainLayout = (LinearLayout) convertView.findViewById(R.id.main_pilayout);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final Place item = getItem(position);
/*
my code assigning the button click listener and assigning the views
*/
return convertView;
}
Am i missing something? im sure this could be a simple fix, but i havent found it yet. any help would be kindly appreciated.
In ListView the individual views for rows, get reused. For example, let's say the window can show up to 10 rows inside the ListView. Now when you scroll down, the 1st view gets out of the window from the top, and a new 11th view comes into the window from the bottom. In order to save memory and CPU power, Android uses the same 1st view for the 11th view. That's the purpose of convertView and the if (convertView == null) {} else {} code.
So the reason why the image is being shown in the 1st item and also in the 11th item, is that they are exactly one view object. To tackle this issue, in the getView() method, you need to reset every attribute of every view and don't rely on the defaults.
So adding a line like the one below, will get rid of the mentioned problem:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// all your code ...
holder.placeImage.setImageResource(0); //<-- This clears any previously set image.
return convertView;
}

How to update view from an onClickListener inside getView of a CustomAdapter in Android

What do I want to achieve?
In the below SS, when user touches 'vote' button, these vertical progress bars (custom) will be set according to the voting percentages retrieved from server for that particular row.
What is the obstacle?
I have onClickListener inside getView of the CustomAdapter, and when I manipulate the ProgressBar instance (which is in ViewHolder Class), supposingly I want to see the updated ProgressBar on ONLY the one row of the listview that has triggered that action, but, I see every once 3 rows that I scroll down.
Example: I clicked first row, so first row has updated its progress bar, but 4th, 7th, 10th... rows are also updated EVEN IF I don't touch 'vote button'.
My Guessing
I think this problem is related to recycling the view, the weird number is 3 in this case but when I make rows smaller it goes '4', so that is the only clue I have.
SS & Codes
ScreenShot: bit.ly/sofscreenshot
Code:
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(layout, null);
holder = new ViewHolder();
//some more initialization
holder.pb1 = (ProgressBar) convertView.findViewById(R.id.leftProgress);
holder.pb2 = (ProgressBar) convertView.findViewById(R.id.rightProgress);
holder.leftVoteButton = (Button) convertView.findViewById(R.id.leftButton);
holder.rightVoteButton = (Button) convertView.findViewById(R.id.rightButton);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.leftVoteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.pb1.setVisibility(View.VISIBLE);
holder.pb2.setVisibility(View.VISIBLE);
/Some codes...
holder.pb1.setProgress(50);
holder.pb2.setProgress(50);
}
});
}
private class ViewHolder {
//some more objects
ProgressBar pb1;
ProgressBar pb2;
Button leftVoteButton;
Button rightVoteButton;
}
All the answers and comments are appreciated, have a great day and thank you.
You're doing it wrong.
The problem is that you need to have a Model somewhere, and change its status. Then the view is updated regarding the model status.
For example, let's say that this is a "StackOverflow" app, and you have a list of answers. The user upvote the second answer. This means that the second element of the List is upvoted.
Now what?
When the adapter is going through your list of object it will "fire" the getView method for that position. Then you have to update that position according to your model. So, if the position is 1, the adapter is trying to show the second Answer, and you have to set the button to "upvoted". Otherwise you have to set it as "normal".
private List<Answer> answers;
public View getView(int position, View convertView, ViewGroup parent) {
// here get your view (or initialize it)
// get the matching answer
Answer answer = answers.get(position);
if(answer.isUpvoted()) {
holder.pb1.setVisibility(View.VISIBLE);
holder.pb2.setVisibility(View.VISIBLE);
} else {
holder.pb1.setVisibility(View.INVISIBLE);
holder.pb2.setVisibility(View.INVISIBLE);
}
holder.leftVoteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.pb1.setVisibility(View.VISIBLE);
holder.pb2.setVisibility(View.VISIBLE);
// not sure on how to get this answer here
// you probably have to go "upper" and manage the click from the ListView
answer.setUpvoted(true);
}
});
}

Update Listview row UI from custom Dialog

I am working on to update image of one button in a row inside custom listview. I have created a custom adapter class for the listview. On click of the button inside one row of listview I have open a custom dialog. Onclick of the OK button of dialog now I want t change the image of the button inside that listview.
Currently I have just made the static button inside the listview and passed the object of that button to the custom dialog method. I am using the simple listview not the fragments.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ItemInfoViewHolder viewHolder;
Log.d("Inside Get View", ""+position);
if (convertView == null) {
convertView = listInflater.inflate(R.layout.iteminfo_view_row, null);
viewHolder = new ItemInfoViewHolder();
viewHolder.itemSelection = (Button)convertView.findViewById(R.id.itemselectionTextview);
convertView.setTag(viewHolder);
}else{
viewHolder = (ItemInfoViewHolder)convertView.getTag();
}
try{
viewHolder.itemSelection.setId(itemsInfo.get(position).getId());
);
viewHolder.itemSelection.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("Item Id"+v.getId());
Toast.makeText(mContext, "Item Button Clicked", Toast.LENGTH_SHORT).show();
int itemId = v.getId();
SelectPopup selectPopup = new SelectPopup(mContext, R.style.myCoolDialog);
selectPopup.selectQuantity(itemsInfo,itemId,viewHolder.itemSelection);
}
});
}catch(Exception e){
e.printStackTrace();
}
return convertView;
}
Here viewHolder.itemSelection is the object of that button which I am passing to the custom dialog method. By this the image is update randomly on the listview on any row.
Please suggest me some better idea to do that.
Brief explanation:
An Adapter acts as a controller of your datamodel, in your case a List<itemsInfo>, and updates its assigned ListView accordingly inside the getView()-method.
Your goal is to change the visual state of the ListView whenever you do a certain action, a click. This is simply done by changing the datamodel behind the Adapter of your ListView whenever you perform your action and ask your ListView to redraw itself with help of the Adapter.
In code:
Add a field to your itemsInfo that will hold a certain state. This can be in any format or form but for now, let's use a boolean called isPressed.
In your getView(), your View will initialize itself depending on this pressed state.
viewHolder.itemSelection.whatevermethodyouwant(itemsInfo.get(position).isPressed)
When you want to change the state of your row, simply change the datamodel at the given position and update the ListView again.
viewHolder.itemSelection.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
itemsInfo.get(position).setPressed(whatever);
notifyDataSetChanged(); // This is a call for your Adapter and will refill the ListView
}
});
This is just pseudo code to explain the flow of events. Hope it will help you to improve your implementation.

ListView Odd/Even Rows Refresh Automatically When Scrolling Down Or Selecting AnotherItem

I use even and odd rows to set backgrond to my listview rows. In my efficientAdapter I set the row background as follows:
public View getView(int position, View convertView, ViewGroup parent) {
vi = convertView;
if (convertView == null) {
vi = inflater.inflate(R.layout.ecran_multiple_row, null);
holder = new ViewHolder();
holder.txIndex = (TextView) vi.findViewById(R.id.txIndex);
holder.txSTitle = (TextView) vi.findViewById(R.id.txSTitle);
holder.btOnOFF = (ImageView) vi.findViewById(R.id.btOnOFF);
vi.setTag(holder);
} else
holder = (ViewHolder) vi.getTag();
/*
* CHANGE ROW COLOR 0 WHITE 1 GRAY
*/
if ( position % 2 == 0) //0 even 1 odd..
vi.setBackgroundResource(R.drawable.listview_selector_odd);
else
vi.setBackgroundResource(R.drawable.listview_selector_even);
/*
* ONE ITEM IN ARRAY
*/
if (data.toArray().length==1){
holder.btOnOFF.setBackgroundResource(R.drawable.air_radio_button_rouge);
}else {
holder.btOnOFF.setBackgroundResource(R.drawable.air_deezer_check);
}
return vi;
}
and in my MainActivity.Class. I select an item using on itemclicklistener() as shown below:
**lvRMultiple.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
imgview = (ImageView) view.findViewById(R.id.btOnOFF);
//And change its background here
imgview.setBackgroundResource(R.drawable.air_radio_button_rouge);
}
});**
When i clicked on an item btnOff image change successfully but when i scroll down it change to default background. Secondly when i click on one item after the other both becomes the new image but i want only the row clicked by the user to change to new image and the previous image are set to default.
All row view of a ListView created by the getView() method of BaseAdpter class. When ever we scroll the ListView all, new viable row create by getView() using recycle. So getView() called again and again when new row is viable on scroll.
There are two solution of your question:-\
You can save the status of ListView
// Save ListView state
Parcelable state = listView.onSaveInstanceState();
// Set new items
listView.setAdapter(adapter);
// Restore previous state (including selected item index and scroll position)
listView.onRestoreInstanceState(state)
And other solution is create RowView at runtime and add it on a Parent Layout by using addView() method.
LayoutInflater inflater = LayoutInflater.from(context);
// You should use the LinerLayout instead of the listview, and parent Layout should be inside of the ScrollView
parentView = (LinerLayout)this.findViewById(R.id.parentView);
for(int i = 0; i<=numberOfRow;i++){
LinearLayout rowView = (LinerLayout)inflater.inflate(R.layout.rowView);
ImageView rowImageView = (ImageView)rowView.findViewById(R.id.rowImage);
rowImageView.setOnClickListener(new View.onClickListListener(){
#Override
public void onClick(){
rowImageView.setImageBitmap(onClickBitmapImage);
}
});
parentView.addView(rowView);
}
Please check this answer Maintain/Save/Restore scroll position when returning to a ListView
More Reference
http://developer.android.com/reference/android/widget/Adapter.html#getView(int,android.view.View, android.view.ViewGroup)
The item changes back to the default background because the view gets recycled. This is the same problems of checkboxes losing their checked state
Check out this answer too see how to handle it:
CheckBox gets unchecked on scroll in a custom listview
As for your second problem, I believe it's already answered here:
highlighting the selected item in the listview in android
Hope it helps

scrolling listview causes buttons to be invisible

I have a list view which contains a button in each row of the list.
Based upon a field, I want to make this button invisible.
My getView method inside adapter is shown below.
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
Activity activity = (Activity) getContext();
View view = convertView;
if (convertView == null) {
LayoutInflater inflater = activity.getLayoutInflater();
view = inflater.inflate(R.layout.listrow, null);
}
final Details details = getItem(position);
Button btn = (Button) view.findViewById(R.id.btn);
if(details.check()) {
btn.setVisibility(View.INVISIBLE);
}
}
When I load this page the data comes correctly. But when simply scroll through this list, then this button is getting invisible. Whats the reason for this? When I remove that if section, then i will get buttons for all rows, even if i scrolls. Is there any problem giving invisible inside getView(). Please reply. Thanks in advance.
Add the following:
if(details.check()) {
btn.setVisibility(View.INVISIBLE);
}
else {
btn.setVisibility(View.VISIBLE);
}
and...it had better use
LayoutInflater.from(getContext())
instead of activity.getLayoutInflater()
set the clickable property of listview false in xml or like:
getListView().setClickable(false);

Categories

Resources