I want to design my UI like the following Instagram's user activity screen.
With the same features (get profile picture, user Name, liked photos click event event).
How to add multiple Images in a list Item and get the click event for the added images?
You will have to create the ImageViews when creating your Row. Which means you will have to do this during getView(). When Creating a new ImageView, make it clickable using iv.setClickable(true) and attach a new clicklistener onto the image, which will handle the opening of the image once you clicked it. If every Image does the same, you can implement the onClickListener in the adapter and add it to every single image. This might be a smart choice if all images do the same, like opening the image you have just clicked.
within the onClick Callback you will have the view the click originated from, so you can access its id or its Tag, which will tell you what image to show.
If you are using custom imageview for imagesthen make the imageview clickable by using this property...
<ImageView
android:clickable="true"
android:onClick="Click"
android:src="#drawable/img">
</ImageView>
I think this will help you...
You have to use adapter to show multiple image in list view and for click
do something like this
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder = null;
if (convertView == null) {
convertView = inf.inflate(R.layout.image, parent, false);
holder = new Holder();
holder.im1 = (ImageView) convertView.findViewById(R.id.imageView1);
holder.im2 = (ImageView) convertView.findViewById(R.id.imageView2);
holder.im1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("i is clicked");
}
});
holder.im2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("2 is clicked");
}
});
convertView.setTag(holder);
} else {
convertView.getTag();
}
return convertView;
}
public class Holder {
ImageView im1, im2;
}
Related
What is best practice to show dialog (like date picker) on control thats in Listview view?
Is it OK to create custom control that embeds dialog logic and place it into Listview views?
EDIT:
For example:
I have textEdit that is placed in Listview. I want to show date picker when user click the textEdit. I want to know what is the best place to put dialog logic to.
You can use setOnItemClickListener in your adapter logic for the ListView.
You then need to create an instance of OnItemClickListener and override the OnClick() method and perform your click logic there. Below is a very simple example to demonstrate this concept.
public class MySimpleListAdapter implements ListAdapter {
// Set your constructors and so on
. . .
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.simple_row_layout, parent, false);
viewHolder = new ViewHolder();
viewHolder.textView = (TextView) convertView.findViewById(R.id.simple_text_view);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
if (adapterData != null) {
viewHolder.textView.setText(item.getTaskTitle()); // This is logic from my SQ Lite database
viewHolder.textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Implement your logic for launching a DialogFragment here
}
});
}
return convertView;
}
}
Then finally, in your Activity where you're displaying the ListView, just set the MySimpleListAdapter to your ListView and you should be good to go.
My code above uses a TextView widget instead of an EditText, but it should be simple enough to replace it with the EditText widget.
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);
}
});
}
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)
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.
Im trying to lock button after user click button on costume list.
the item of list fetched from hayoola and then i use viewholder to show data
to user in list.
if user click accept or refuse button. the result will be passed to hayoola and
the selected button will be disabled
Problem is after user click button wrong button getting disable. and after five click all remaining button getting disable too.
here is my adapter code :
static class myviewholder {
TextView textfromhayoola;
ImageButton buttonaccpet;
ImageButton buttonrefuse;
}
public View getView(int position, View convertView, ViewGroup parent) {
try {
final myviewholder viewHolder;
final int itemlocation = position;
if (convertView == null) {
convertView = inflater.inflate(R.layout.listforuser, null);
viewHolder = new myviewholder();
viewHolder.textfromhayoola = (TextView) convertView.findViewById(R.id.textfromhayoola);
viewHolder.buttonaccpet= (ImageButton) convertView.findViewById(R.id.buttonaccpet);
viewHolder.buttonrefuse= (ImageButton) convertView.findViewById(R.id.buttonrefuse);
convertView.setTag(viewHolder);
}else{
viewHolder = (myviewholder) convertView.getTag();
}
HashMap<String, String> myhayooladata= new HashMap<String, String>();
myhayooladata = data.get(position);
if (myhayooladata != null) {
viewHolder.textfromhayoola.setTag(myhayooladata.get("id_textfromhayoola"));
viewHolder.textfromhayoola.setText(myhayooladata.get("textfromhayoola"));
viewHolder.buttonaccpet.setTag(getItemId(position));
viewHolder.buttonrefuse.setTag(getItemId(position));
viewHolder.buttonaccpet.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
performOnBackgroundThread(new Runnable() {
public void run() {
passdatatohayoola(viewHolder.textfromhayoola.getTag().toString(),"accpet");
}
});
arg0.findViewWithTag(viewHolder.buttonaccpet.getTag()).setEnabled(false);
arg0.findViewWithTag(viewHolder.buttonrefuse.getTag()).setEnabled(false);
}
});
viewHolder.buttonrefuse.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
performOnBackgroundThread(new Runnable() {
public void run() {
passdatatohayoola(viewHolder.textfromhayoola.getTag().toString(),"refuse");
}
});
arg0.findViewWithTag(viewHolder.buttonaccpet.getTag()).setEnabled(false);
arg0.findViewWithTag(viewHolder.buttonrefuse.getTag()).setEnabled(false);
}
});
Hehe. Do you think that. Just "n/number of your records" view(s) will be created?
Assume that:
If you have 100 records and 10 rows will be draw.
And 10 rows won't re-draw.
Button accept of row 1 is disabled that mean Button accept of row 11 + n is the same. :D
May be that's your problem.
And Please read this:
Let I tell you something about ViewHolder pattern.
When you load data to ListView or GridView or something like these.
If your data has 1000 records, ... The ListView doesn't load 1000 records. It's just load "n records". "n" is number of record which compatible with your screen device.
Example: n = 10.
When you scroll down, The ListView will load more data. In this case, each row (view of row) will re-draw.
And with ListView which has large data, when use scroll up or down, you will see your app will be slow... because view is re-drawing.
And ViewHolder is the pattern which help you solve that problem.
When you use ViewHolder pattern, Just "n" (in this example n = 10) views will be created.
So, In your problem. I can tell you that:
May be you are implemented ViewHolder is incorrect.
OK. Let I tell you about the solution.
if (convertView == null) {
//You just findView and set for view
// viewHolder = new ViewHolder();
// viewHolder.yourBtn = convertView.findViewById(R.id.some_view_id);
// convertView.setTag(viewHolder);
} else {
//Right here, you will get viewHolder, because convertView is not null. It mean the viewHolder is existed.
}
And right here, It mean every time you will set data (You won't cache data, just cache VIEW)
Assume that Your data is an object and object has property which stand for status of button.
MyObject {
boolean objStatus;
}
and when you set data
viewHolder.yourBtn.setEnable(instanceOfMyObject.objStatus);