I am trying to set one button to enabled and a different one to disabled once it is clicked on the listView. There are 2 buttons and I am trying to change them in the onClick in the getView function of my adapter.
Here is the onCLick of one of them.
holder.upButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("Event", "Up");
View parentRow = (View) v.getParent();
ImageButton uButton = (ImageButton) parentRow.findViewById(R.id.upImageView);
ListView listView = (ListView) parentRow.getParent();
final int position = listView.getPositionForView(parentRow);
if (activity.equals("Host"))
{
} else {
}
uButton.setEnabled(false);
}
});
thank you
If you try to change the view inside an onClick() function, it will not work.
You didn't post a lot of code, so I will just describe the correct code.
First, your adapter needs to model the enabled state of the two buttons. In other words, for each list item you need two booleans, one for each button.
In your view binding method, you need to access the two booleans and set the enabled state of each button based on its model boolean value.
In your onClick(), you need to flip the state of the two booleans and call notifyDataSetChanged() to refresh the list with the new button states.
Related
if (RFidList.size() >0){
for (String s: RFidList){
RFidTagValueList.remove(s);
}
}
mTimeAdapter.notifyDataSetChanged();
dialog.dismiss();
when choose multiple items in recyclerview checkbox not working / and am use private ArrayList<String> data = new ArrayList<>();
You can't move and delete from the list. The best option to do this is to have an array that will remember the state of the checkbox. Scrolling through your recycler view will always change the state of the checkbox and maybe won't remember it. The way to do this is to add an array of boolean
private boolean[] checkStates;
then inside your constructor of the adapter do this.
checkStates = new boolean[data.size()];
This way you'll create an array of boolean filled with FALSE value the same size your data array is. Now, inside your adapter when you are binding your view do this for the checkbox.
holder.checkbox.setChecked(checkStates[position]);
Also, don't use onCheckedChangeListener on checkbox inside adapter. This will be called even when you scroll and it will change whatever you are doing inside the function. What you can do is override onClick for the checkbox, but there is something tricky here. When you click the checkbox to check it, inside the onClick method the view will have the state as it is already checked so to follow this do it like this:
holder.checkbox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Checkbox c = (CheckBox) v;
checkStates[position] = c.isChecked();
}
});
I wrote this from my head and maybe there are some mistakes but you'll get the point. The animation of the check state will be handled you just need to handle changes inside the checkStates array.
Now your checkbox will always have the state it had before. After this, you can create a function to delete items from your data.
public void removeItems() {
ArrayList<YOUR-MODEL> items_to_delete = new ArrayList<>();
for (int i = 0; i < checkStates.length(); ++i) {
if (checkStates[i]) items_to_delete.add(data.get(i]);
}
data.removeAll(items_to_delete);
notifyDataSetChanged();
checkStates = new boolean[data.size()];
}
This works if your data is a type of ArrayList. I think this is the best way to go.
I have a GridView adapter displaying a grid of Buttons. Now I want to set up an OnClickListener for my buttons but of course they don't have their own R.id I can access as they are added to the grid via the adapter, rather than a layout.xml.
I tried to use OnItemClickListener as follows:
m_onItemClickListener = new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int pos, long l) {
switch(pos) {
case MyConstants.POS_OF_BUTTON_1:
// Do stuff...
break;
case MyConstants.POS_OF_BUTTON_2:
// Do stuff...
break;
}
}
};
But to my understanding you can't use a clickable or focusable item with OnItemClickListener. How do I get round this? Thanks!
There are more elegant ways to do this whole thing (starting from using a RecyclerView with a GridLayoutManager instead of a GridView), but if you're looking for the quick and easy solution to use with what you already have, this is what you can do:
First of all, you should set some ID on your buttons, they don't have to come from R.id (although it would be preferable if you inflated the views from a layout, with an ID defined there, and used a ViewHolder).
Worst case, you can just define constants in your adapter for the IDs you want to use for each kind of button (e.g. static final int DELETE_BUTTON = 1;), and then set these IDs on the buttons manually, in code.
Then you can pass a simple OnClickListener (not OnItemClickListener), which handles clicks of all these different buttons in a single item, to your adapter, and make the adapter set the listener on each of these buttons, for each of the item views in the grid.
You will also need to set the position of the item as a tag on the button view itself, so that when the click happens, you can determine for which item the click happened.
Sample code as follows:
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View v) {
Object tag = v.getTag();
if (!(tag instanceof Integer)) {
// Show error message or just throw an exception.
}
int position = (Integer) tag;
// We get the item at this position, to know which one to use
Item item = adapter.getItem(position);
switch (v.getId()) {
case DELETE_BUTTON:
// Delete stuff here
break;
case EDIT_BUTTON:
// Edit stuff here
break;
...
}
}
};
adapter.setOnClickListener(listener);
Then, in the getView method of the adapter, you need to set this listener on each of the buttons and also set the position of the item as a tag on the buttons. This way, you will be able to figure out to which item the button belongs to, in the listener code above.
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
...
deleteButton.setId(DELETE_BUTTON);
deleteButton.setOnClickListener(listener);
deleteButton.setTag(i);
...
}
In general, I sincerely urge you to also look into the ViewHolder pattern, and RecyclerView and GridLayoutManager when you have time. Most of this will translate there as well.
EDIT
In order to make multiple Views clickable/focusable inside a list/grid item, you need to set the descendantFocusability attribute to blocksDescendants on the root view of the item, either simply in the XML, or in code via:
viewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
I am using AndroidSwipeableCardStack to do a tinder like interface with a 5 star rating system. When I click on a button that is meant to change the image. The image changes three cards later not in the current card.
This is the project I used: https://github.com/wenchaojiang/AndroidSwipeableCardStack
I assume it is to do with it pre-loading the next card as a recyclerview normally does but I am really not sure.
This my adapter below, you can see at the bottom I call setimageresource on the one star rating image button onclicklistner. I set a Log.d and the button click is registering immediately upon click but the change in the image resource appears only after 3 cards have been swiped.
Edit: So I noticed that regardless of the project I imported, my adapter is only extending ArrayAdatper. So I guessed that the problem might be in the getView method and that I might need to override something else (not sure). But the important point, I checked the position in getView by logging the position and sure enough it said position 0,1,2,3 without anything being swiped away. This is analogous to the offset of the setImageResource so I believe they are interlinked but unfortunately that doesn't bring me any closer to an answer.
Thanks for your help.
public class SongPreviewCardsDataAdapter extends ArrayAdapter<SongDatabaseMappingAdapter> {
public SongPreviewCardsDataAdapter(Context context, int resource) {
super(context, resource);
}
ImageButton oneStarRating;
#Override
public View getView(int position, final View contentView, ViewGroup parent) {
// Initialise Song Views
SongDatabaseMappingAdapter item = getItem(position);
TextView songName = (TextView) (contentView.findViewById(R.id.songNameTextView));
songName.setText(item.getSongTitle());
com.mikhaellopez.circularimageview.CircularImageView songImage = (CircularImageView) contentView.findViewById(R.id.songImageView);
String ImageURL = (item.getPictureURL());
Picasso
.with(this.getContext())
.load(ImageURL)
.into(songImage);
// Initialise Rating Buttons
oneStarRating = (ImageButton) contentView.findViewById(R.id.ratingButton1);
// Create OnClickListners for Ratings Buttons
oneStarRating.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
oneStarRating.setImageResource(R.drawable.starfull);
Log.d("Star", "Star Clicked");
}
});
return contentView;
}
}
getView can be called at any time on any item, so if you want something to stay set on a view, you have to model it.
I don't know if your SongDatabaseMappingAdapter class is something you can change or not, but I'll assume you can change it.
Add a variable to your item class, like boolean mOneStar. Getter/setter left as an exercise for the reader.
In getView() make your item final so you can refer to it in the onClick callback:
final SongDatabaseMappingAdapter item = getItem(position);
Use the variable in getView to set up your view:
oneStarRating = (ImageButton) contentView.findViewById(R.id.ratingButton1);
oneStarRating.setImageDrawable(null); // clear out recycled value
if (item.isOneStar()) {
oneStarRating.setImageResource(R.drawable.starfull);
}
In your OnClickListener, set the property on the item and call notifyDataSetChanged():
oneStarRating.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("Star", "Star Clicked");
item.setOneStar(true);
notifyDataSetChanged();
}
});
The main point is: Never change a view from an event handler. Always change the item from the event handler then call adapter.notifyDataSetChanged(), and always change your view in getView() based on the item.
I have a horizontal recyclerview having radio button as recyclerview item. I have to select all other radio button as false without currently selected radio button. So I have done -
View.OnClickListener rbClick = new View.OnClickListener() {
#Override
public void onClick(View v) {
RadioButton checked_rb = (RadioButton) v;
if (lastCheckedRB != null && lastCheckedRB != checked_rb) {
lastCheckedRB.setChecked(false);
}
lastCheckedRB = checked_rb;
}
};
mainHolder.radioBtnTrip.setOnClickListener(rbClick);
Its working fine when i have 4 to 5 items. But when it has more than 5 items then always multiple radio button is selected as true because of view recycle. Given photo indicate that first item is selected but also 10th radio button is selected when I scroll.
How to resolve the row item position issue. I must have to select only one radio button at a time and select all other radio button of recyclerview as false.
Override the method getItemViewType to format the viewholder in many different way based on the value ( or whatever ) of the view
#Override
public int getItemViewType(int position) {
// example
return 0;
}
then, in your onBindViewHolder method
#Override
public void onBindViewHolder(Adapter.ViewHolder viewHolder, int position) {
if( this.getItemViewType(position)==1){
// layout #1
}else{
// layout #2
}
}
Understand the way recyclerview or listview works
You have to store the checked status somewhere to update when the bindview is called , where you can set the checked status to true.
Listview or RecyclerView will reuse view from any index on scrolling.
Same view that you have selected before cannot be expected on the same index when your scrolling back.
A simple way to do this is to create a property in the respective model and then inside onBindViewHolder() set the radio buttons checked property according to the model
Just wondering if what I'm trying to do is possible. So i have a custom adapter for a listview. It contains a textview and two buttons. I would like one of the listview buttons to remain hidden unless a specific button is pressed on the main activity.
So far I have the listview buttons performing their intended function but I have no idea how I would even begin to get what I'm wanting.
Sorry, for clarification, I have one button completely separate from the listview that is just always there. When I press this button I would like to toggle the visibility of a button that is on each listview item all together. The best example of this that I can think of is having a list of items and a button that can toggle off the 1. 2. 3. 4. that comes in front of each item.
Create a method in your adapter for knowing you have clicked the button from your main activity like this
public void buttonIsClicked(){ //in your adapter
buttonhide.setVisibility(visibility?View.VISIBLE:View.GONE);
}
And call this method from your activity on btnclick.
like
yourAdapter.buttonIsClicked();
and call this method for notifying the adapter about the change.
yourAdapter.notifyDatasetChanged().
or
You can use an interface for listening to the clicks in main activity and implement that listener in your adapter
Set visibility gone to the button you want to hide by calling code
buttonhide.setVisibilty(VIEW.GONE);
hide it in oncreate() of your activity and make it shown on the button click event by calling code buttonhide.setVisibilty(VIEW.VISIBLE);
Below is the code
btnView.setVisibility(View.GONE);
yes it is possible to do that.
First have a Model class to back the listview data and keep a flag in that model which indicates whether to show the button in that row's data model. On certain condition change that model's flag and call notifyDataSetChanged() on adapter.
Ex:
class Model{
String label;
boolean showBtn;
}
in adapter's getView()
Model model = list.get(position)
if(model.showBtn){
btn.setVisibility(View.VISIBLE);
}else{
btn.setVisibility(View.GONE);
}
in Activity
disableButton(){
modelList.get(0).setShowBtn(false);
adapter.notifyDataSetChanged();
}
This code will hide button in first row
Add a Boolean value in your dataset which represent the Visibility state of the button.
public class Dataset {
private boolean visible;
public boolean isVisible() {
return this.visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
//..more items
}
Then in your getView method of the Adapter check this Boolean value to show/hide the button.
boolean visibility = yourDataset.get(position).isVisible();
yourButton.setVisibility(visibility?View.VISIBLE:View.GONE);
And when the Button outside of your listview is clicked Update your dataset. And call yourAdapter.notifyDatasetChanged().
What you are attempting is: manipulating the visibility of the button declared in the Adapter from the containing activity. Simple, put a controlling variable in the activity and pass it a parameter to adapter.
Boolean mShowButton; //a controlling variable
void onCreate(Bundle savedInstanceState) {
...
mAdapter=new MyAdapter(...,mShowButton);
mButton.setOnClickListener(actionShow );
}
OnClickListener actionShow = new OnClickListener() {
#Override
public void onClick(View button) {
mShowButton=true;
mAdapter.notifyDataSetChanged();
mListView.invalidateViews();
}
};
And do this in your adapter,
Boolean showButton;
public MyAdapter(Context context, List<String> myList, Boolean showButton) {
...
this.showButton=showButton;
}
public View getView(int position, View rowView, ViewGroup parent) {
...
if(showButton){
mButtonTwo.setVisibility(View.GONE);
}else{
mButtonTwo.setVisibility(View.VISIBLE);
}
}