Good afternoon,
So I have a custom ListView with a custom Adapter that has an item that is a checkbox for each row. In my getView I implemented setOnCheckedChangeListener and the onCheckedChanged handlers for my checkbox.
Now, the problem is:
Whenever I check/uncheck one of items of the list I would like to update an external TextView with the values I want (assume that for each item there is a price associated so I want to show below the list the total price).
How am I supposed to reach the "external" view from the getView of adapter? What other workaround do I have?
I leave here some part of my code on the getView function of my custom adapter:
CheckBox name = (CheckBox) view.findViewById(R.id.product);
name.setText(content[i][0]);
final View v = view;
final int position = i;
name.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton group, boolean isChecked) {
setCheckedItem(position);
EditText quantity = (EditText) v.findViewById(R.id.product_quantity);
content[position][3] = quantity.getText().toString();
Iterator<String> it = getCheckedItems().values().iterator();
Double total = 0.0;
for (int i=0;i<getCheckedItems().size();i++){
Integer quantity_p = Integer.parseInt(getItem(position)[3]);
Double price = Double.parseDouble(getItem(position)[2]);
total += quantity_p*price;
}
TextView total_price = (TextView) findViewById(R.id.total_products_price);
total_price.setText(total.toString());
}
});
Notice the last two lines: I know I can't call the findViewById but I don't know what to do by now. Any suggestions would be good, thank you.
Put your adapter class in the activity class.
Declare TextView total_price in main activity class
then
total_price = (TextView) findViewById(R.id.total_products_price);
in your on create.
Then you can access total_price inside onCheckedChanged. Try this, it may work.
You can pass your TextView to an Adapter in constructor. After this you can have a private static class which will implement CompoundButton.OnCheckedChangedListener like this:
private static class MyOnCheckedChangedListener
implements CompoundButton.OnCheckedChangedListener {
TextView myView;
public MyOnCheckedChangedListener (TextView viewToChange) {
myView = viewToChange;
}
#Override
public void onCheckedChanged(CompoundButton group,
boolean isChecked) { ... }
}
After this just setOnCheckedChangedListener new MyOnCheckedChangedListener (myTextView) (the one you passed to Adapter) and you're ready to go.
This is just a thought and theory here. But can you make a static method in your activity, where the TextView you want to change is declared at, and in that method write a code for changing your text, the way you want it to change.
And then call that static method from BaseAdapter.
I say static so you dont have to make a new instance of an entire class.
My could be doing like this:
You can pass textview reference to your adapter constructor and use it to change its value.
But good approach is to have a interface implemented in your activity and in its callback method update textview. For you adapter pass activity reference in constructor and use its reference to call interface callback method.
a) Have interace as
public Interface UpdateTextviewInterface
{
void updateTextview(String value);
}
b) Let your activity implement this interface
public MainActivity extends Activity implments UpdateTextviewInterface
and override that method.
c) Pass activity reference to adapter constructor. Using activity reference call updateTextview method to update your textview.
Related
I am having adapter class, In that, I need to pass invoiceId to an Activity Class. I have seen some example like pass-through interface, but I lost track on following the code procedure.
Here Is My Adapter Class extends BaseAdapter
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
companyName = ct.getSharedPreferences("prefs", 0);
Log.d("test", "" + deliveryListBeans.size());
LayoutInflater inflater = (LayoutInflater) ct.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.list_vew_for_delivery_order, null);
TextView invoice = (TextView) v.findViewById(R.id.invoice);
final TextView delivery = (TextView) v.findViewById(R.id.do_delivery);
final DeliveryListBean dlb = deliveryListBeans.get(position);
invoice.setText(dlb.getInvoiceNo());
}
delivery.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ct.startActivity(new Intent(ct, EmployeesListForPopUp.class));
DeliveryOrdersListAdapter deliveryOrdersListAdapter=new DeliveryOrdersListAdapter(EmployeesListForPopUp.this);
}
});
}
Here is My Activity Class
public class EmployeesListForPopUp extends Activity {
private List<EmployeeIdNameBean> employeeIdNameBeans = new ArrayList<EmployeeIdNameBean>();
ListView listView;
SharedPreferences companyName;
EmployeePopUpAdapter employeePopUpAdapter;
private ImageView img1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_employees_list_for_pop_up);
I need to get invoiceId from Adapter Class. How?
You need to pass context of the activity in adapters constructor.
Then set activity.invoiceid value in clickevents of adapter.
One simple way is that you write a method in MainActivity
public void setInvoiceId(int invoiceId) {
// do what you want with invoiceId
}
and pass the instance of your activity to adapter
DeliveryOrdersListAdapter adapter = new DeliveryOrdersListAdapter(EmployeesListForPopUp.this);
and get it in your adapter and keep it
EmployeesListForPopUp myActivity;
public MyAdapter(EmployeesListForPopUp activity) {
myActivity = activity;
}
and where you need to pass invoiceId just call the method of main activity
myActivity.setInvoiceId(invoiceId);
General way of implementing it:
In the adapter class, where you set text to invoice TextView, you also can add a tag to it. Put attention - despite every item in the list is build from the same prototype, the tag (as well as text) will be uniq. The best way is to use "position" as value of the tag: invoice.setText(dlb.getInvoiceNo());
invoice.setTag(Integer.valueOf(position).toString());
You need to make your items in the list clickable (this is out of the scope of this question). So, when you click on some item - you can retrieve any data it has, and specifically tag - getTag();.
Then you send Intent to other activity, providing the tag as extra message. So that activity will "know" which item in the array list it is related to (i.e. tag == position, right?). And continue from there.
I implemented simple project that illustrates it. This project is simple demo and illustration of working with ArrayList adapter,
displaying the item in the ListView, clicking on some item and display relevant data in separated activity. Please download it and try (min API 21). Basic description is available in README file.
The project is here on the GitHub:
(corrected path)
https://github.com/everall77/ArrayListSimpleExmpl
I have a ViewHolder than contains, among other widgets, a SeekBar. The SeekBar has a Listener, which is added during the onCreateViewHolder call.
Since the onBindViewHolder method is used to configure the Views held by the ViewHolder, how can that Listener then act upon the new dataset represented by the ViewHolder's Views?
Is it OK to add a member variable of type Object to the ViewHolder, which contains a reference to the dataset, so that the Listener can then take this object and modify a variable in the dataset during SeekBar-changes? Or is this an Anti-Pattern?
The dataset object referenced by that member variable would then get swapped out on every onBindViewHolder in order to "point" to the currently represented dataset.
If u r using a RecyclerView.ViewHolder then u do understand that usual ViewHolder pattern's getView() method is replaced here by 2 methods: onCreateViewHolder() and onBindViewHolder(). Method onCreateViewHolder() stands for creating VH or getting it from tag and onBindViewHolder() stands for filling VH's views with corresponding data. Understanding this the only place you shoud set the listener is onBindViewHolder() method.
If your question is about creating a Listener every time the onBindViewHolder() fires - its not a good idea. You better create one instance of a listener as (adapter) class field and use it. Usually I'm setting something to a target View's tag and this "something" is an object I need inside a listener.
private final View.OnClickListener onCancelClick = new View.OnClickListener() {
#Override
public void onClick(View v) {
final SwipeLayout swipeLayout = (SwipeLayout) v.getParent().getParent();
swipeLayout.close();
}
};
and iside of a getView() or onBindViewHolder():
viewHolder.btnSwipeMenuCancel.setTag(swipeLayout);
viewHolder.btnSwipeMenuCancel.setOnClickListener(onCancelClick);
using a tag:
viewHolder.btnSwipeMenuReply.setTag(message);
viewHolder.btnSwipeMenuReply.setOnClickListener(onReplyToAuthorClick);
private final View.OnClickListener onReplyToAuthorClick = new View.OnClickListener() {
#Override
public void onClick(View v) {
final Message message = (Message) v.getTag();
activity.replyToMessageAuthor(message);
}
};
This is a my use case. I have an activity with a listview and a textview. The textview is the sum of all numbers on the listview, the listview has all the numbers.I have a custom adapter for this case.
On each row of the listview, I have a button. This button will change the number on this row.
what I want to do is this:
when user clicks the button, the value on each row is changed - doable.
the sum on the textview also changes accordingly.
This is a simplified example. In reality, I also have a constraint that I have a data model to represent the data on each role. I am not able to extend the data model to DataSetObserver.
any help?
You should create a listener, which listens for touch on your increment button and inside it call a method of the class extending an interface you created.
To make it easy, in your adapter you will have:
public interface OnIncrementListener{
onNumberIncremented();
}
private OnIncrementListener mListener;
//This is inside getView method of your adapter
myButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mListener.onNumberIncremented();
}
});
Then your activity
public class MyActivity extends Activity implements OnIncrementListener {
//inside onCreate
myAdapter.setOnIncrementListener(this);
//end onCreate
#Override
public void onNumberIncremented() {
//Change value of your TextView here
}
}
Could someone please explain the different ways of making checkbox list and saving the checked option? It would be nice if you could attach examples. I am using arraylist to save input, what are the other ways?
final CharSequence[] items = {};
final ArrayList seletedItems = new ArrayList();
Define your ListItem object to have a 'checked' field
class ListItem{
boolean isChecked=false;
}
In your list adapter's getView attach a onCheckedChangeListener to the CheckBox and change the checked state of your object. something like:
final MessageItem Message=getItem(position);
message.setText(Message.text);
//set data
select.setOnCheckedChangeListener(null); //important so that when reusing the view the old listener isn't called
select.setChecked(Message.selected);
select.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// TODO Auto-generated method stub
Message.selected=isChecked;
}
});
You can create a custom class for objects like,
public class entity
{
public boolean isChecked;
//Any other variables can also be created
}
On check box selection change the value of
entityobj[index].isChecked=true/false;
Apply a custom list adapter,
in adapters getview() method you can check for isChecked value and then either check or uncheck the respective checkbox,
using this your selection will persist while scrolling also..
Hope it will help...
I'm developing a Androidapplication using ListView.
ListView have a one file in each and every ListItem. Here, I have set onItemClickin ListView. So, that if user clicks the ListItememail application gets open and attach the particular file in email. Its for the single File, this gets implemented and working fine.
Now I want attach the multiple file in email. i.e. the implementing the CheckBoxin each ListItemand checked items have to attached into the Mail.
I know its possible because its very similar to the file manager application that checking the multiple file and deleting the all file by clicking the single Button. But don't know how to do.
In you ListAdapter create a SparseBooleanArray
private SparseBooleanArray checkStatus;
This SparseBooleanArray stores the checked items. Now in getView do the following
#Override
public View getView(int position, View view, ViewGroup parent) {
ViewCache viewCache;
if (view == null){
viewCache = new ViewCache();
view = layoutInflater.inflate(R.layout.list_box, null, false);
viewCache.checkBox = view.findViewById(R.id.check_box);
viewCache.checkBox.setOnCheckedChangeListener(onCheckedChangeListener);
//other views in the list box
...........
}
vewCache = (ViewCache)view.getTag();
viewCache.checkBox.setTag(position);
viewCache.checkBox.setChecked(isChecked(position));
//set other views
........
}
This is the class ViewCache
private static class ViewCache{
CheckBox checkBox;
//other views in the list box
.......
}
This method checks whether the position is checked
private boolean isChecked(int position){
return checkStatus.get(position, false);
}
This is the onCheckChangeListener
CompoundButton.OnCheckedChangeListener onCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
checkStatus.put(((Integer)compoundButton.getTag()), b);
}
};
Finally you can get the checked items from the SparseBooleanArray checkStatus. Think it will help you.
You can try implementing your own ArrayAdapter. Initialize it with an array of your file objects and use it in the list view.
Next make a list of indexes that is visible by the adapter and can be manipulated from the outside. In your onItemClick method you have the position of the clicked item. If it's in that list remove it, otherwise - insert it. Let's call that list selection.
Next in your adapter's getView method construct a view with a checkbox inside. Again you have the current position, because it's passed as an argument. Set the checkbox state depending on the presence of the position in selection.
Finally implement your button's onClick so that it does whatever you do with your file objects only for those objects of your file_array whose positions are in your selection.
Hope that helps
In the above answers Sreejith has given a good explanation of how to store the states of the checked items in the list view using a SparseBooleanArray. This solves the first part of your problem.
The second part regarding the passing of the states of these items to the other activities can be achieved using the Application class.
Application class:
Base class for those who need to maintain global application state. Sometimes you want to store data, like global variables which need to be accessed from multiple Activities - sometimes everywhere within the application. In this case, the Application object will help you.
Here is a sample code for this:
public class TopClass extends Application {
private static TopClass topClass;
public TopClass getInstance()
{
return topClass;
}
#Override
public void onCreate ( )
{
super.onCreate();
topClass = this;
}
public ArrayList<String> arrList = new ArrayList<String>();
}
You need to set tag android:name="TopClass" in the application manifest file under the application tag. Something like this:
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:name="TopClass" >
....
....
Here is how you can access it from the activity:
TopClass top = (TopClass)getApplicationContext();
top.arrList.add("StackOverflow");
Now you can access the same variable from other activities similarly.