I have looked other questions but none of them fulfill what I need.
I have a listview showing a list of objects (alarms) that have some textviews and a checkbox. As you can imagine, this checkbox is to activate and deactivate that alarm.
When I arrive to this screen (alarms list), it checks the active state in the database, so some of the checkboxes are checked and some other not.
What I need is to click in the checkbox and change the state in the database for that alarm at the moment. Not checking the state of all checkboxes before leaving the screen!!! I have read solutions using selectedItems or Holder class, but are not suitable for me.
I think I need to define the onClick event in the checkbox (in the AlarmAdapter), but the list of alarms is in the activity (ListAlarms), so I don't know how to "tell" the list of alarms "this is the checkbox (alarm) that has been clicked, then update its active state".
Any idea? Maybe controlling the action in the row (with OnItemClickListener) instead of clicking the checkbox?
Thanks a lot!!!
I think if you read the response here you will have your answer:
How to get selected list items from a Listview with checkBox and Custom Adapter?
Finally, I have done a non-clean solution:
This code in the adapter:
CheckBox active = (CheckBox) view.findViewById(R.id.cb_active);
active.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
a.toggle();
boolean exists = false;
for(Alarm aux : modifiedAlarms){
if(aux.getId() == a.getId()){
exists = true;
}
}
if(!exists){
modifiedAlarms.add(a);
}
else{
//this is to guarantee that the alarm has the same state than the added one.
a.toggle();
modifiedAlarms.remove(a);
a.toggle();
}
}
});
active.setTag(a);
And this code in the activity, when leaving the screen:
ImageView back = (ImageView)findViewById(R.id.iv_back);
back.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ArrayList<Alarm> modified = adapter.getModifiedAlarms();
for(Alarm a : modified){
dataalarms.activeAlarm(a.getId(), a.getActive());
}
finish();
}
});
If anybody knows how to get the onClick event in the activity, it would be nice to answer here.
Thanks! :)
This is where the custom object comes in. You create an array of these objects, and then you set a flag in the onClick event of your checkbox in the adapter. Then you can access this object and check the flag. Sorry for creating new answers, but my rep isn't high enough to comment.
Related
sorry if bad english
I'm kinda new in android development.
I'm working on an app and i need to fill a custom ListView. each of the ListView items got a Delete Button, which removes them from the list, the problem is that i need to keep that removed item.
A little background:
i am working on a "Monster Generator" app that just gives you a monster (name, desc, etc) from a "bag" (consider just a List) and places it on another list inside a java object i made, the object can keep track of the monster generated and the monsters left in the bag. i already make a functional prototype, using only TextViews but i tried to make it as ListView, and there is the problem.
in my Custom Adapter in the getView method i have
Button btnDelete = (Button) view.findViewById(R.id.btn_delete);
btnDelete.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
items.remove(position); // this item i need to keep somehow in the activity
notifyDataSetChanged();
// I need to keep the item removed, ready to use in the activity
//and i don't know how
}
});
ArrayList<Monster> listToKeep = new ArrayList<>();
Button btnDelete = (Button) view.findViewById(R.id.btn_delete);
btnDelete.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
listToKeep.add(items.get(position));
items.remove(position);
notifyDataSetChanged();
}
});
well, i kinda resolve it:
First of all, i think the situation of my problem may be to specific, anyway i'll post my solution.
Second, thanks to you for posting an answer.
apparently i have a really bad understanding of objects, at least in java (i am ashamed).
i just needed to change my CustomAdapterClass contructor to accept my "game logic"
public CustomAdapter(GameActivity activity, List<Monster> items, GameLogic gamelogic){...}
my "GameLogic" (this just for clarify my situation) has two ArrayList, one of MonstersInBag list(monsters that are not in game), and another of MonstersInGame list.
The MonstersInGame list, is the list i am using to fill the listview.
So i add the removed item of the listview and add it to the GameLogic - MonstersInBag, and updated a textView in my activity with a public method.
buttonDelete.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
Game.getMonsterGameBag().add(items.remove(position));
notifyDataSetChanged();
activity.UpdateMonsterNumber();
}
});
I hope it help anyone with a specific situation like this.
I have added checkboxes dynamically in my onCreate() method. When one or more of them are checked I want two buttons to be displayed. I am new to working with Android, but from what I can tell it won't work to do this check (see if checkboxes are checked) in the same method as the checkboxes are added, i.e. onCreate(), because they can't be found, i.e. haven't been created yet? If this is the case, in what method should I do the check? I want to add the checkboxes at startup of the activity and to check if the boxes are checked all the time.
The checkboxes are added in displayEntries(db).
Here is my onCreate():
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DatabaseHandler db = new DatabaseHandler(this);
displayEntries(db);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent(MainActivity.this, AddActivity.class); //FromActivity.this
startActivity(i);
}
});
checkChecked();
}
checkChecked():
public void checkChecked() {
//Check whether items have been checked
TableLayout tl = (TableLayout) findViewById(R.id.entry_table);
for (int i = 0; i < tl.getChildCount(); i++) {
View child = tl.getChildAt(i);
if (child instanceof CheckBox) {
CheckBox checkBoxChild = (CheckBox) child;
Log.d("Checkbox", "Checkbox is found");
if (checkBoxChild.isChecked()) {
Log.d("Checkbox", "working!");
Button button1 = (Button) findViewById(R.id.button_edit);
button1.setVisibility(View.INVISIBLE);
Button button2 = (Button) findViewById(R.id.button_delete);
button2.setVisibility(View.INVISIBLE);
}
}
}
}
(At the moment I am trying to make the buttons invisible as you could see above, since I didn't want to "hardcode" in the layout file that they should be invisible to start with - thought that might make it impossible to change? But that's a later question...)
EDIT: I realised my mistake was thinking that the checkboxes where children of my TableLayout. They were in fact children of the rows in the TableLayout. Now that I managed to locate the actual checkbox, I can make the buttons disappear by setting them as invisible when creating them and visible onClick. The remaining problem is that the buttons of course stay visible even if all buttons are unchecked again. Any ideas on how to toggle the buttons on and off depending on if any of the checkboxes are checked or not?
Did not understand your question at first. Please ignore my first answer.
If you want to listen on a check box you might want to try
myCheckBox.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View view) {
//do something
}
});
Anything you do in onCreate() will be re-created with each activity cycle.
Therefore you might want to store the state of the check box, and change that state when someone clicks on it.
EDIT after #Ingrid comment:
Looks like there are two problems that need to be solved. One is saving the state and restoring it in on activity/fragment cycle, the other is setting the buttons visible based on condition of N checkboxes.
Assuming you are working with a database object you have an option to use dynamically created check boxes to manipulate the data in your Database Object. The checkboxes represent Boolean values in your DB object or list of objects. Since the checkboxes are dynamic and represent things in your DB, it does not make much sense to store their state in two places. If you do that, things will get out of sync and you will have a nasty bug. Rather rely on the DB object instead. Thus, update your DB object when you click on a checkbox. In onResume() retrieve that DB object (from bundle or DB depending on your architecture) and set your checkboxes / button state based on the state of the DB object.
You can use onPause() to persist your db object. or persist it on click of the check box so your don't have to wary about losing the state in-between. use onResume to setup your UI component base on the current state of the db object. Last but not least, when you update your db object check if you need to show/hide the buttons. (That is if there are on fixed number of buttons but N number of check boxes.
Hope this helps.
//Use shared preference to save.
SharedPreferences preferedName=getSharedPreferences("SavedName", Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = preferedName.edit();
editor.putboolean("SavedName",value);
editor.apply();
editor.commit();
//and to retrive.
SharedPreferences preferedName=getSharedPreferences("SavedName", Activity.MODE_PRIVATE);
boolean chkNull =preferedName.getString("SavedName",false);
and use the boolean as the value of the checkbox.
you can see check CompoundButton because CheckBox inherit from CompoundButton
https://developer.android.com/reference/android/widget/CompoundButton.html#setOnCheckedChangeListener(android.widget.CompoundButton.OnCheckedChangeListener)
checkBoxChild.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
}
});
Hello I'm having an issue getting all of the items from my adapter in my fragment. To be more specific I am using a ScaleInAnimatorAdapter along with my Customer Adapter and when I attempt to get my checkbox items from the below posted code, within my Fragment, I only seem to get the visible items on screen.
private View.OnClickListener onAllClick = new View.OnClickListener() {
#Override public void onClick(View v) {
int count = listAdapter.getItemCount();
for (int i = 0; i < count; i++) {
View mChild = listTopics.getChildAt(i);
if( mChild != null ) {
Log.d(TAG,"getItemCount(): " + i );
CheckBox cBox = (CheckBox)mChild.findViewById(R.id.topic_chk);
cBox.setChecked(((CheckBox) v).isChecked());
Log.d(TAG,"isChecked" + cBox.getTag());
cBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(((CheckBox) v).isChecked()) {
checkboxAll.setChecked(false);
}
}
});
}
}
}
};
Essentially I am attempting to create a check all feature from the fragment, so that when this is clicked all of the checkbox items from the adapter are checked. I got that to work with the code I presented however the main issue is that I only get the items visible on the screen, so when I scroll to my other items they are not checked. Thus I am wondering if there is a better way or another way for me to get all of the items
Adapters are meant to bind underlying data stores to views; they generally shouldn't be used to store data themselves (except for having a copy of the data for view binding purposes) nor should they perform actions on data.
Instead, you should be modifying the underlying data, then updating the adapter through whatever mechanism you are already using. (Loaders, custom setters with notifyDataItemChanged, etc.).
Basically you can't. It'll be reusing the UI views.
You need to set a flag in all your data list objects, call notifyDataSetChanged() and onBindViewHolder check that flag and use it to check uncheck
if(listAdapter.getItem(position).getIsChecked())
viewHolder.checkBox.setChecked(true);
else
viewHolder.checkBox.setChecked(false);
Ok. Thank you all for those who have replied you helped me grasp something really basic and important that had alluded me.
I got it to work, so for anyone who might read this post, here is my solution:
Create necessary methods and field to update your data in a model (ie, private is_checked, set_checked(), is_checked(), etc)
In your adapter onBindViewHolder, you will set your holder checkbox to be associated to the data so something like:
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
obj.setSelected(buttonView.isChecked());
}
});
holder.checkBox.setChecked(obj.isSelected());
Then in your fragment or activity I just have a click listener on my main checkbox, and then when checked I loop through my data list, and using the model method I update my data and just simply use listAdapter.notifyDataSetChanged()
You are doing it wrongly.
You should update the adapter instead of updating the check box view.
What you can do , you can create a field in adapter data holder .
And whenever you change the selection,just update the field or multiple field and finally refresh the view.
Iv'e got a custom Listview implemented in this particular class, it looks like
[Image/Textview/Checkbox]
When someone clicks on the text is should launch another class, this is working at the moment, however when someone clicks a checkbox I want to update an array that stores the current state of all the checkboxes, I tried doing that via using a onCheckedChanged method within the custom adapter however it doesn't work as the position variable isn't final. So two questions
1 within the adapter is their a way to get the position of the Checkbox so I can change the right position in the array, and
2 If not is their another way to update the array somewhere else without disrupting the current functionality of the onClick.
Here is my onCheckedChanged within my adapter
CheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton but, boolean b) {
// TODO Auto-generated method stub
if(but.isChecked())
{
deleteList[???] = true;
}else{
deleteList[???] = false;
}
}
});
Have a look a this method. You can set a tag to a view containing any object you wish, which in your case may be the integer value associated with the CheckBox's row.
So when you create your CheckBox:
but.setTag(new Integer(position));
This would change your if statement to:
if (but.isChecked()){
deleteList[((Integer) but.getTag()).intValue()] = true;
} else {
deleteList[((Integer) but.getTag()).intValue()] = false;
}
Let me know if this helps!
I found a similar question about scrolling listview and button click but it did not help me. My issue is:
I have a listview with custom rows. I have two different states of listview; the switch between the states is a button at the bottom of the screen. The second state has delete buttons in every row. When I click on delete button in a specific row, that row is removed from database and listview is updated. Everything works great except I need to click the delete button twice in order for it to work. Below is my code for handling the clicks. flag==1 is the second state of the listview.
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
View main = parent.getChildAt(position);
TextView delete = (TextView)main.findViewById(R.id.delete_button);
if(flag==0){
switchToItemsView(id);
}
if(flag==1){
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mDbHelper.deleteList(id);
updateListView();
}});
}
}
I tried to set parent view's focusableInTouchMode attribute to false as suggested in another post but it did not help.
If you can help me solve this I will be grateful,
Thank you in advance.
Probably you have focus. Remove it.
android:focusableInTouchMode="true"
android:focusable="true"
You need to declare the onClickListener before the actual flag check; in your case the view changes and with that the flag, and the listener is set. The next click actually triggers the listener.
Not related, but you should change your second if to an elseif since there is no way it would be called if the first one is called.
After spending hours I figured out how to do it:
I moved my click listener from my main activity class to my custom ListAdapter class and modified it a little like below;
deleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int rowid = Integer.parseInt(rowIds.get(position));
mDb.deleteList(rowid);
lists.remove(position);
notifyDataSetChanged();
}
});
Now it works great. When I click delete button it removes the list both from the ArrayList (the one used in ListAdapter) and from database.