How to identify associated widget when list item is clicked? - android

I have been able to create a ListActivity that displays a header and a footer, and sandwiched between these a custom layout that contains on each row three checkboxes and a Contact name (reading from the Contacts database). I use a SimpleCursorAdapter to display this info. My problem has been getting the OnListItemClicked()* to fire. I click in the ListView (on the checkboxes AND on the name of the Contact) and my breakpoint is never reached. So: What must I do to get that to fire. I AM setting it, like so:
lv.SetOnListItemClicked(etc);
I think it is; I'm not at my dev machine right now
But even if I am able to get the click event to fire, how will I be able to identify the associated checkboxes? They are named ckbx1, ckbx2, and ckbx3 (or so) in the layout file, but there will be (Contacts.Count) of them, so how can I positively identify which ones have been clicked?
My other option is to dynamically create the widgets in the Activity's OnCreate().
My pseudocode for this is the following, and I'm open to suggestions/feedback on whether this makes or is [not] the best way to go about it:
OnCreate() {
Cursor c = getContacts();
for (i = 0, i == c.Count, i++) {
int id = getContactID(i);
CheckBox ckbx1 = new CheckBox();
ckbx1.Tag = id;
ckbx1.OnClick = Checkbox1Click();
CheckBox ckbx2 = new CheckBox();
ckbx2.Tag = id;
ckbx2.OnClick = Checkbox2Click();
CheckBox ckbx3 = new CheckBox();
ckbx3.Tag = id;
ckbx3.OnClick = Checkbox3Click();
TextView tv = new TextView();
tv.Text = getContactName(i);
}
Checkbox1Click() {
int ContactID = (CheckBox)object.Tag;
switch (ContactID)
case 1:
WriteToDB(1, Option1);
case 2:
WriteToDB(2, Option1);
...
}
This (especially the CheckboxClick event handler) is obviously very rough, but I think you can get the drift of where I'm going with this - saving the "checked" state of the Checkboxes to a SQLite DB so that I know Contact1 wants email (or twitter feed, or whatever the other two checkboxes indicate).
So is my previous method salvageable, or should I go down this new path (or veer off a little from that?)

Usually i uses View.setTag to identify a view instance. For example,
checkBox.setTag("listItem1");

Related

Why in RecyclerView findViewByPosition() returns null on EditText

I have an Activity, which has a RecyclerView and save Button. Each item (football match) of the RecyclerView contains some text (name of teams) and EditText, where user enters data (actually bet the match). My goal is to save those scores to the list in the Activity, when user clicked on save Button.
I implemented this method in Activity, which actually get particular item from LinearLayoutManager and then get data from EditText, but the findViewByPosition() method (or getChildAt() there are different way to do this) sometimes returns null.
I saw another answers on similar question, but they didn't help me. Maybe my strategy is wrong, because I made whole my logic in Activity (better to do this in Adapter?) and I get though all of my items in RecyclerView even if only in one user entered the score.
private List<Bet> getUserBets() {
View betView;
Bet betItem;
EditText userBet1;
EditText userBet2;
int numberOfMatches = rvBetsAdapter.getItemCount();
List<Bet> bets = new ArrayList<>();
for (int i = 0; i < numberOfMatches; i++)
{
betItem = rvBetsAdapter.getItem(i);
betView = linearLayoutManager.findViewByPosition(i);
userScore1 = (EditText) betView.findViewById(R.id.result1); // <- NPE appears
userScore2 = (EditText) betView.findViewById(R.id.result2);
//here i checked whether the editText is empty and other stuff
bets.add(betItem);
}
return bets;
}
How do I fix it? I suppose I should do something in onBindViewHolder method in my adapter, but what exactly?
I would really appreciate any help.
You should add to your Bet model variable which holds EditText value for example editTextValue.
And access it using list in adapter list like this end use EditText value from there. rvBetsAdapter.getItem(i).editTextValue
editTextValue can be set using TextWatcher.afterTextChanged() callback
You can only find or get views that are visible on the screen.
before using findViewByPosition(2)
go to position 2 by recyclerView.scrollToPosition(2);
if you want to change value of this views, The best way is get your item in list
yourModel item = (yourModel) itemList.Get(2)
item.Name = "Edited";
yourAdapter.notifyItemChanged(2);

Is it possible to add long press listener to CheckBoxPreference?

The answers in this thread are not helping in any way.
I have one requirement where I want to do something when user long presses on CheckBoxPreference. I am dynamically creating the CheckBoxPreference inside activity. I am using below piece of code to populate the view:
m_PreferenceScreen = getPreferenceManager().createPreferenceScreen(this);
m_PreferenceCategory = new PreferenceCategory(this);
m_CheckBoxPreference = new CheckBoxPreference[m_Cursor.getCount()];
int i = 0;
while (m_Cursor.moveToNext()) {
//Create checkbox instances here
m_CheckBoxPreference[i].setOnPreferenceChangeListener(this);
m_PreferenceCategory.addPreference(m_CheckBoxPreference[i++]);
}
setPreferenceScreen(m_PreferenceScreen);
On what I am trying to achieve?
I have few entries in database. I want to populate a list of checkboxes corresponding to each entry in database(I am able to do it with above code). Now my requirement is, when user long presses on any checkbox, it should do something(Say, open a dialog box).
Is this thing doable with above piece of code?
I will also appreciate any alternate solution. However, I would prefer going with the first approach.
I'm not sure if CheckBoxPreference has a long press component or not. You might want to evaluate your UX to see if you can replace the action with a different UI component. Perhaps it is a regular preference that when click opens your details as well as a checkbox that can be checked.
If this doesn't suit your needs you can manually create checkbox views that can automatically load/update the shared preference object. I believe the standard view checkbox has the ability to be long pressed. It might be something to sample out since I've never directly tried long pressing a checkbox. If you cannot you might need to create a checkbox and a separate component that contains the text to be long pressed.
I managed to do this. The below trick works for me.
ListView listView = getListView();
listView.setOnItemLongClickListener(this);
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
ListView listView = (ListView) parent;
ListAdapter listAdapter = listView.getAdapter();
Object obj = listAdapter.getItem(position);
if (obj != null && obj instanceof View.OnLongClickListener) {
View.OnLongClickListener longListener = (View.OnLongClickListener) obj;
return longListener.onLongClick(view);
}
return false;
}

Referring to programmatically created UI elements in Android

I was wondering how to refer to an View if I create it programmatically.
I have to create new passenger Views with "Add Passenger" and respectively "Remove Passenger" buttons to my app. The promts are kept LinearLayouts called "#+id/passenger" which have two EditTexts called "#+id/passenger_name" and "#+id/passenger_weight". Those are then kept in a yet another parent LinearLayout called passenger_layout that can hold all the passenger LinearLayouts in a bunch
Adding new passengers is easy, but I have no idea how to refer to the newly created elements. I guess they get a identifier of some sort automatically? I'd prefer them to be "passenger_name%" and "passenger_weight%", where % is an index _passengerCount.
addPassenger.Click += delegate {
//Add to index
++passengerCount;
//Prep new passenger layout
var newLayout = new LinearLayout(Activity);
//Set LayoutParameters from the existing passenger LayoutParameters
newLayout.LayoutParameters = newPassenger.LayoutParameters;
//Prep the new EditTexts
var name = new EditText(Activity);
var weight = new EditText(Activity);
//Set the EditTexts' LayoutParameters from existing LayoutParameters
name.LayoutParameters = new ViewGroup.LayoutParams(passengerName.LayoutParameters);
weight.LayoutParameters = new ViewGroup.LayoutParams(passengerWeight.LayoutParameters);
//These cleary don't work :<
// name.Id = Resources.GetIdentifier( "passenger_name" + passengerCount, "id", Activity.PackageName);
// weight.Id = "passenger_weight" + passengerCount;
//Add EditTexts to the new passenger layout and then and then add the new passenger to the parent LinearLayout
newLayout.AddView(name);
newLayout.AddView(weight);
passengerLayout.AddView(newLayout);
Log.Debug(GetType().FullName, "Add clicked");
};
That is my click delegate to create a new passenger, but again even if I create them like this I don't know how I can find them later if I have to for example remove them or get the name or weight data.
How do I refer to programmatically created UI elements?
When you create a view, try giving it some ID, and holding that ID as a static reference somewhere.
Then, you could simply call the containing view's findViewById(MY_VIEWS_ID) and get the view.
Of course, alternatively, you could always hold a reference to the view you created somewhere in your code when you create it. If you're afraid of memory leaks, you could use WeakReference.
Hope this helps.
You could maintain a static variable within the Activity that will contain the UI element after it gets initialized.
Something like:
// Definition
private static TextView textViewToSave = null;
textViewToSave = // create the TextView programatically.
// Do stuff with the saved TextView
textViewToSave.setText("O Hai world!");

How to add a select all button to a custom Listview

I have a custom listView in my app I would like to implement my select all button I have created.
My ListView looks like.
[(Image)(Text)(CheckBox)]
I have looked at some similar questions, the most common answer was with the user of the notifyDataSetChanged () method, iv'e tried researching and implementing without any luck, I was wondering can you think of a way round it or give me an example of how I can implement the method
A simple way of doing this would be to iterate through the ListView to get each item View, then check it off. I have provided some sample code below given that you are able to acquire the ListView as sampleListView and have an id of the checkbox of checkBoxId:
// Loop through all the items in the list view
for(int viewIndex = 0; viewIndex < sampleListView.getCount(); viewIndex++)
{
// Get the current list item
View listItem = sampleListView.getChildAt(sampleListView.getFirstVisiblePosition() + viewIndex);
// Get the checkbox within the list item
CheckBox currentBox = (CheckBox)listItem.findViewById(R.id.checkBoxId);
// Check the checkbox
currentBox.setChecked(true);
}
You could place this code within the OnClickListener() of the button and it should do the trick.
I couldn't get the above answer to work, so I used parts of another answer and found the answer.
I added this this globally.
ListView list;
//\\ 0 = None set \\// 1 = Select all \\// 2 = Un-Select all//\\
int selState = 0;
Then in the onClick method I used
selState = 2;
list.invalidateViews();
selState being equal to what function you want to do
In the Adapter, this is final part of code
switch(selState)
{
...
case 2:
CheckBox.setChecked(false);
break;
}

AlertDialog.Builder problem with accessing a specific row

I've been working on this application but have come across a problem that I have been unable to figure out. I have a listview that is populated with the contents from an adapter, and each row has their specific information (Uniform). The problem comes when I try to retrieve the value of a checkbox that is found in that particular row.
The code in question is below:
I build an AlertDialog object so I can get my information from the user. My layout code consists of a LinearLayout in horizontal orientation with 3 elements an image, text, check box. I build my AlertDialog with R.layout.listview_layout, which is a custom layout that I made.
One thing I tried to do is get the CheckBox View from the adapter, however; when I look at it via cb.isChecked(), no matter what row i'm on its always unchecked (aka false). In order to debug this further I took the same adapter and retrieved the text via the same methodology and it returned specific information about that row, as it should.
Any ideas how I can handle this?
Simply Put:
I would just like to get the value of the CheckBox at each given row
c = help.returnContacts();
AlertDialog.Builder ab = new AlertDialog.Builder(this);
ab.setTitle("Select contacts");
final SimpleCursorAdapter adapter = new SimpleCursorAdapter(
getApplicationContext(), R.layout.listview_layout, c,
new String[] { ClientOpenDbHelperUtility.COL_NAME,
ClientOpenDbHelperUtility.COL_SEL }, new int[] {
R.id.txt_name, R.id.cb_select });
ab.setAdapter(adapter, null);
ab.setPositiveButton("Confirm", new Dialog.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Cursor c = adapter.getCursor();
for (int i = 0; i < adapter.getCount(); i++) {
CheckBox cb = (CheckBox) adapter.getView(i, null, null)
.findViewById(R.id.cb_select);
TextView t = (TextView) adapter.getView(i, null, null)
.findViewById(R.id.txt_name);
Log.d("DEBUG", "Checked = " + cb.isChecked());
Log.d("DEBUG", "Message = " + t.getText().toString());
if (cb.isChecked()) {
help
.updateSelection(
c
.getColumnIndex(ClientOpenDbHelperUtility.COL_UID),
true);
} else {
help
.updateSelection(
c
.getColumnIndex(ClientOpenDbHelperUtility.COL_UID),
false);
}
}
c.close();
help.closeAll();
}
});
ab.show();
}
Thanks for reading!
You shouldn't call getView directly. Doing so generates a fresh view (or recycles and overwrites an old one) based on the contents of your database.
Also, once your rows scroll off the top or bottom of the screen they will be recycled for use in new rows that appear. All of your data but the currently visible rows are most likely to have already vanished by the time your onClick method gets called.
You have two options:
Persist changes immediately to the database - set an OnClickListener on your checkbox or on the row and update your database on each click event.
Save changes to an instance variable and then apply later - define a Map<Integer, Boolean> changes instance variable for your activity and call changes.put(position, isChecked) whenever there is a click. Then when your user clicks "Apply" or whatever your onClick is, go through changes and persist each one to the database. It's basically the same as what you have now except you would be using a stable object to store the unsaved changes.

Categories

Resources