I'm developing an Android 3.1 application.
I have created my custom ArrayAdapter with an ArrayList. Form is a custom class with two fields: name and FormId.
Here is my ArrayAdapter code:
public class FormAdapter extends ArrayAdapter<Form>
{
private Context context;
private int layoutResourceId;
private List<Form> forms;
private ArrayList<Integer> checkedItemsPosition;
private Button downloadButton;
public ArrayList<Integer> getCheckedItemsPosition()
{
return checkedItemsPosition;
}
public String[] getSelectedFormsId()
{
String[] ids = new String[checkedItemsPosition.size()];
int i = 0;
for(Integer pos : checkedItemsPosition)
{
Form f = forms.get(pos.intValue());
ids[i] = f.FormId;
i++;
}
return ids;
}
/**
* Called when selected forms has been downloaded and save it locally correctly.
*/
public void updateFormsNotDownloaded()
{
for (Integer pos : checkedItemsPosition)
{
remove(forms.get(pos.intValue()));
}
checkedItemsPosition.clear();
notifyDataSetChanged();
}
public FormAdapter(Context context, int textViewResourceId,
List<Form> objects, Button downloadButton)
{
super(context, textViewResourceId, objects);
this.context = context;
this.layoutResourceId = textViewResourceId;
this.forms = objects;
this.checkedItemsPosition = new ArrayList<Integer>();
this.downloadButton = downloadButton;
}
#Override
public int getCount()
{
return forms.size();
}
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
Log.v("FormAdapter", "getView.postion: " + position);
View row = convertView;
if (row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
}
Form f = forms.get(position);
if (f != null)
{
CheckBox checkBox = (CheckBox)row.findViewById(R.id.itemCheckBox);
if (checkBox != null)
{
checkBox.setText(f.Name);
checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked)
{
//Form f = forms.get(position);
if (isChecked)
{
//checkedItems.add(f.FormId);
checkedItemsPosition.add(new Integer(position));
}
else
{
//checkedItems.remove(checkedItems.indexOf(f.FormId));
checkedItemsPosition.remove(checkedItemsPosition.indexOf(new Integer(position)));
}
downloadButton.setEnabled(checkedItemsPosition.size() > 0);
}
});
}
}
return row;
}
}
List items are custom items with a checkbox. On checkedItemsPosition I store checked items position.
My problem is on updateFormsNotDownloaded method. Why am I getting an UnsupportedOperationException?
I can only think of one reason. The List<> implementation you pass into the ArrayAdapters constructor does not support remove(). You can use an ArrayList to fix that.
If for some reason you are using Arrays.asList() to construct your list from an array you are getting a list which cannot be modified.
The size of the
* {#code List} cannot be modified, i.e. adding and removing are unsupported
Related
How to hide an item from other spinners that is currently selected in one spinner?
I've tried removing the items via ArrayList of strings and ArrayAdapters, but I've noticed as soon as it's removed from the list, the selection is no longer referenced to the list item (because it does not exist anymore).
Now suppose, I have 4 spinner that are created dynamically and they all have the same ArrayList as their resource and now i would like to use this adapter to fetch the position of the selected item from 1 spinner and then hide it from 3 other spinners.
for (int i = 0; i < numberOfStops; i++) {
AddStopView stopView = new AddStopView(getActivity());
stopView.setCallback(BaseBookingFragment.this);
stopView.setPassengerNames(extraPassengerNames);
stopViews.add(stopView);
parent.addView(stopView, viewPosition);
}
In above code i am creating Stop Views dynamically and each Stop View having Passenger Name spinner. And these all spinners have the same ArrayList as their resource.
piece of code from AddStopView.java
public AddStopView(Context context) {
super(context);
initialize();
}
public void setCallback(StopViewCallback callback) {
this.callback = callback;
}
public void setPassengerNames(List<String> passengerNames) {
this.passengerNames = passengerNames;
passengerAdapter.setNames(passengerNames);
}
private void initialize() {
inflate(getContext(), R.layout.view_stop, this);
passengerAdapter = new ExtraPassengerAdapter(getContext());
passengerAdapter.setNames(passengerNames);
nameSpinner.setAdapter(passengerAdapter);
nameSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (view == null) {
return;
}
passengerName = (String) view.getTag();
if (position != 0)
callback.updatePassengerList(AddStopView.this, (position - 1));
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
code of call back of nameSpinner.setOnItemSelectedListener
#Override
public void updatePassengerList(AddStopView addStopView, int position) {
for (String passName : extraPassengerNames) {
if (addStopView.getPassengerName().equals(passName)) {
extraPassengerNames.remove(passName);
break;
}
}
for (AddStopView stopView : stopViews) {
if (!stopView.equals(addStopView))
stopView.setPassengerNames(extraPassengerNames);
}
}
code from ExtraPassengerAdapter.java
public class ExtraPassengerAdapter extends BaseAdapter {
private List<String> names = new ArrayList<>();
private Context context;
public ExtraPassengerAdapter(Context context) {
this.context = context;
names.add(get0Position());
}
public void setNames(List<String> names) {
this.names.clear();
this.names.add(get0Position());
this.names.addAll(names);
notifyDataSetChanged();
}
#Override
public int getCount() {
return names.size();
}
#Override
public String getItem(int position) {
return names.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView = (TextView) LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_stop, parent, false);
String name = getItem(position);
textView.setText(name);
textView.setTag(name);
return textView;
}
private String get0Position() {
return context.getString(R.string.passenger_name);
}
}
I think the right way to solve you problem is to create one list with all possible options and 4 lists with 4 adapters for each spinner. When something selected you update each list according to logic you described and call adapter.notifyDataSetChanged() for each adapter.
I am facing an issue where I am getting ArrayIndexOutOfBound on photoViewAttacherList.get(position). Now I can easily handle by catching the error, but I am not able to understand why it is happening at the very first place. Here is the code of the adapter. It's strange because I am adding the new PhotoViewAttacher in instantiate function which will be called for every new item added.
public class FullImagePagerAdaptor extends PagerAdapter {
private final LayoutInflater inflater;
private final ArrayList<String> urls;
private final Context context;
private final ArrayList<String> descriptions;
private ArrayList<PhotoViewAttacher> photoViewAttacherList;
private TogglePagingListener togglePagingListener;
public FullImagePagerAdaptor(Context context, ArrayList<String> urls, ArrayList<String>
descriptions, TogglePagingListener togglePagingListener) {
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.urls = urls;
this.context = context;
this.descriptions = descriptions;
photoViewAttacherList = new ArrayList<>();
this.togglePagingListener = togglePagingListener;
}
#Override
public int getCount() {
return urls.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#Override
public Object instantiateItem(ViewGroup container, final int position) {
View v = inflater.inflate(R.layout.fragment_full_image, container, false);
TextView description = (TextView) v.findViewById(R.id.txt_full_image_description);
ProgressBar progressBar = (ProgressBar) v.findViewById(R.id.progress_bar_full_image);
ImageView imageView = (ImageView) v.findViewById(R.id.full_image_view);
if (descriptions != null && descriptions.get(position) != null) {
description.setText(descriptions.get(position));
}
Log.d("sg","Instantiating Pager:with position" + position);
ImageUtility.loadImage(context, urls.get(position),
GlobalVariables.IMAGE_TYPE.URL, 0, 0,
imageView, progressBar);
photoViewAttacherList.add(new PhotoViewAttacher(imageView));
// THIS IS WHERE ARRAYINDEXOUTOFBOUND EXCEPTION IS GETTING RAISED
photoViewAttacherList.get(position).setOnMatrixChangeListener(new PhotoViewAttacher.OnMatrixChangedListener() {
#Override
public void onMatrixChanged(RectF rect) {
if(isImageZoomed(position))
togglePagingListener.disablePaging();
else
togglePagingListener.enablePaging();
}
});
container.addView(v);
return v;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
photoViewAttacherList = null;
container.removeView((View) object);
}
public boolean isImageZoomed(int pos) {
return checkZoom(pos) != 1.0;
}
public float checkZoom(int pos){
return photoViewAttacherList.get(pos).getScale();
}
public interface TogglePagingListener {
public void enablePaging();
public void disablePaging();
}
From your code I understand one thing that, you want to add a new PhotoViewAttacher object to your existing list and add a listener setOnMatrixChangeListener to that object.
For this you are adding that object in list and then accessing the same again from list, rather you can have an object created and add to list and to the same object you can add event listener. This is a clean approach.
position should also be recalculated to know exactly where the element was inserted but this is final so you can not change it so declare a new variable for it.
Snippet:
PhotoViewAttacher photoObj = new PhotoViewAttacher(imageView);
photoViewAttacherList.add(photoObj);
final int newPositionInserted = photoViewAttacherList.size() - 1; //Recalculating the position here to know exactly where the object was added
// Here you can use the object which was created so you do not need to worry about the index also
photoObj.setOnMatrixChangeListener(new PhotoViewAttacher.OnMatrixChangedListener() {
#Override
public void onMatrixChanged(RectF rect) {
if(isImageZoomed(newPositionInserted))
togglePagingListener.disablePaging();
else
togglePagingListener.enablePaging();
}
});
It seems setChecked is invoked every time I click the preference and the selected item changes but in the dialog the selected item remains unchanged for some reason. I have no idea what's going on. Relaunching the application can make the selected item change but that's not the expected behavior. :~
Here's the class:
public class IconListPreference extends ListPreference {
private Context mContext;
private LayoutInflater mInflater;
private Drawable[] mEntryIcons = null;
private String mKey;
private int selectedEntry = -1;
public IconListPreference(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public IconListPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
mContext = context;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.IconPreference, defStyle, 0);
int entryIconsResId = a.getResourceId(R.styleable.IconPreference_entryIcons, -1);
if (entryIconsResId != -1) setEntryIcons(entryIconsResId);
mInflater = LayoutInflater.from(context);
mKey = getKey();
a.recycle();
}
public void setEntryIcons(Drawable[] entryIcons) {
mEntryIcons = entryIcons;
}
public void setEntryIcons(int entryIconsResId) {
TypedArray icons_array = mContext.getResources().obtainTypedArray(entryIconsResId);
Drawable[] icon_ids_array = new Drawable[icons_array.length()];
for (int i = 0; i < icons_array.length(); i++) icon_ids_array[i] = icons_array.getDrawable(i);
setEntryIcons(icon_ids_array);
icons_array.recycle();
}
#Override
protected void onPrepareDialogBuilder(Builder builder) {
CharSequence[] entries = getEntries(), entryValues = getEntryValues();
if (entries.length != entryValues.length) throw new IllegalStateException
("ListPreference requires an entries array and an entryValues array which are both the same length");
if (mEntryIcons != null && entries.length != mEntryIcons.length) throw new IllegalStateException
("IconListPreference requires the icons entries array be the same length than entries or null");
IconListPreferenceScreenAdapter iconListPreferenceAdapter = new IconListPreferenceScreenAdapter();
if (mEntryIcons != null) {
String selectedValue = getPreferenceManager().getSharedPreferences().getString(mKey, "");
for (int i = 0; i < entryValues.length; i++) {
if (selectedValue.compareTo((String) entryValues[i]) == 0) {
selectedEntry = i;
break;
}
}
builder.setAdapter(iconListPreferenceAdapter, null);
}
super.onPrepareDialogBuilder(builder);
}
private class IconListPreferenceScreenAdapter extends BaseAdapter {
public int getCount() {
return mEntryIcons.length;
}
class CustomHolder {
private CheckedTextView text = null;
CustomHolder(View row, int position) {
text = (CheckedTextView) row.findViewById(android.R.id.text1);
text.setText(getEntries()[position]);
text.setChecked(selectedEntry == position);
if (mEntryIcons != null)
text.setCompoundDrawablesWithIntrinsicBounds(mEntryIcons[position], null, null, null);
}
}
public Object getItem(int position) {
return getEntries()[position];
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) convertView = mInflater.inflate(Resources.getSystem()
.getIdentifier("select_dialog_singlechoice_holo", "layout", "android"), parent, false);
CustomHolder holder;
final int p = position;
holder = new CustomHolder(convertView, position);
convertView.setTag(holder);
convertView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
v.requestFocus();
getDialog().dismiss();
IconListPreference.this.callChangeListener(getEntryValues()[p]);
SharedPreferences.Editor editor = getPreferenceManager().getSharedPreferences().edit();
editor.putString(mKey, getEntryValues()[p].toString());
selectedEntry = p;
editor.apply();
}
});
return convertView;
}
}
}
And res/values/attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="IconPreference">
<attr name="entryIcons" format="reference" />
</declare-styleable>
</resources>
EDIT: Updated my code with a bugfix, but still don't work sthough. A temporary solution found: invoke setValue((String) newValue) in OnPreferenceChangeListener.onPreferenceChange.
OK I finally get it. You need to do the following to make your customized preference work:
callChangeListener before setting user-supplied values;
notifyChanged if you need to update user interface, i.e. whenever value changes.
I have the following problem.
I created a custom list preference for displaying a textview with an additional image.
Nearly everything works fine except of the following problem:
The original list preference scrolls to the position which is currently selected, but my custom list preference does not show this behaviour. If I replace the custom list preference with the android version (or in my case the holoeverywhere version), everything works fine.
Therefore, I think that the bug must be in my current implementation of the custom list preference.
public class CustomListPreference extends ListPreference {
private CustomListPreferenceAdapter customListPreferenceAdapter = null;
private Context mContext;
private LayoutInflater mInflater;
private CharSequence[] entries;
private CharSequence[] entryValues;
private Map<String, Boolean> rButtonMapping = null;
private SharedPreferences prefs;
private SharedPreferences.Editor editor;
public CustomListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
mInflater = LayoutInflater.from(context);
rButtonMapping = new HashMap<String, Boolean>();
prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
// init the button mapping with the default values
for (int i = 0; i < Data.getData().length; i++) {
rButtonMapping.put(Data.getData()[i], false);
}
// Set the current selected value to true
String currentSelectedValue = prefs.getString(
SettingsActivity.CUST_PREF_KEY, "TEST1");
rButtonMapping.put(currentSelectedValue, true);
editor = prefs.edit();
}
#Override
protected void onPrepareDialogBuilder(Builder builder) {
entries = getEntries();
entryValues = getEntryValues();
if (entries == null || entryValues == null
|| entries.length != entryValues.length) {
throw new IllegalStateException(
"ListPreference requires an entries array and an entryValues array which are both the same length");
}
customListPreferenceAdapter = new CustomListPreferenceAdapter();
builder.setAdapter(customListPreferenceAdapter,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
}
private class CustomListPreferenceAdapter extends BaseAdapter {
public int getCount() {
return entries.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView,
ViewGroup parent) {
View row = convertView;
if (row == null) {
row = mInflater.inflate(R.layout.custom_list_preference_row,
parent, false);
}
TextView text = (TextView) row
.findViewById(R.id.settings_tv_test);
text.setText(entries[position]);
try {
InputStream ims = mContext.getAssets().open(
"pics/" + entryValues[position] + ".png");
BitmapDrawable d = new BitmapDrawable(mContext.getResources(),
ims);
d.setTargetDensity(mContext.getResources().getDisplayMetrics().densityDpi);
text.setCompoundDrawablesWithIntrinsicBounds(d, null, null,
null);
} catch (IOException e) {
text.setCompoundDrawablesWithIntrinsicBounds(null, null, null,
null);
}
RadioButton rButton = (RadioButton) row
.findViewById(R.id.settings_rb);
// If the current position is checked we also check the current
// value
rButton.setChecked(rButtonMapping.get(entryValues[position]));
row.setClickable(true);
row.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
for (String currentString : rButtonMapping.keySet()) {
rButtonMapping.put(currentString, false);
}
// Set the current selected value to true
rButtonMapping.put((String) entryValues[position], true);
// Also send the selected value to the editor
editor.putString(SettingsActivity.CUST_PREF_KEY,
(String) entryValues[position]);
editor.commit();
getDialog().dismiss();
}
});
rButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
for (String currentString : rButtonMapping.keySet()) {
rButtonMapping.put(currentString, false);
}
// Set the current selected value to true
rButtonMapping.put((String) entryValues[position], true);
// Also send the selected value to the editor
editor.putString(SettingsActivity.CUST_PREF_KEY,
(String) entryValues[position]);
editor.commit();
getDialog().dismiss();
}
});
return row;
}
}
}
I also did research here on Stackoverflow and Google, but no one seems to have this problem.
Does anyone see what the problem is?
I suggest to replace the call to setAdapter with a call to setSingleChoiceItems method of the builder:
builder.setSingleChoiceItems(adapter, adapter.getSelectedItem(),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
The adapter.getSelectedItem() would be a method that returns the index of the current selected row.
To scroll to a selected item in a ListPreference, just use the setSelection method of Android ListView in the onCreateDialogView() method of your custom ListPreference class. For example:
public class CustomListPreference extends ListPreference {
#Override
protected View onCreateDialogView() {
ListView mListView = (ListView) view.findViewById(android.R.id.list);
// Scroll to selected item in ListView.
mListView.setSelection(findIndexOfValue(getValue()));
}
}
I'm new to android and I have following problem
I have a ListView. The ListView is filled with data from an ArrayList. I added a CheckBox to every row.
After clicking on a "Resume-Button" I want to write the selected items to a SQLliteDB (the db works fine - I tested it with static data).
My question is now:
How can I get the checked items from the list?
Thx everyone for help!
Best regards
kyp
You can use this ListView method getCheckedItemPositions() to get all the checked positions. Make sure that the child view in your ListView actually implements the Checkable interface otherwise the checkmark information will not be passed along to the ListView.
You can go through the list, using a for loop and getItemAtPosition(int).
For each row you just check if the item is checked, isChecked() for a checkbox. Without seeing the code that is as specific as I can get. If this is not clear enough then post some code about how/what items are stored in the listView
Hope this helps!
But i figured it out myself.
I only wanted to select the row by clicking on the checkBox view.
I modified my custom Array Adapter
Here is my code:
public class ContactAdapter extends ArrayAdapter<Contact> implements OnClickListener{
private static HashMap<Integer, Boolean> teamItems = new HashMap<Integer, Boolean>();
int count = 0;
private List<Contact> items;
private int mode;
CheckBox add_to_team;
static int counter = 3;
public ContactAdapter(Context context, int textViewResourceId, List<Contact> objects, int mode) {
super(context, textViewResourceId, objects);
// TODO Auto-generated constructor stub
this.context = context;
this.mode = mode;
this.items = objects;
}
#Override
public View getView(int position, View convertView, final ViewGroup parent) {
View v = convertView;
if(v == null) {
//get a reference to the LayoutInflator
LayoutInflater li = (LayoutInflater)getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//and inflate our XML into the View
v = li.inflate(R.layout.list_contacts_item, null);
}
String race = items.get(position).race;
String nick = items.get(position).nick;
String name = items.get(position).name;
final int pos = position;
if(v!= null) {
// Do the work for the other views
// MODE 1 = SELECTION-MODE
if(mode == 1) {
add_to_team.setVisibility(0);
try {
if(count!=0) {
boolean b = teamItems.get(pos);
if(b==false) {
add_to_team.setChecked(false);
}
else {
add_to_team.setChecked(true);
}
}
} catch (NullPointerException e) {
}
add_to_team.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
teamItems.put(pos, arg1);
count++;
}
});
} else {
add_to_team.setVisibility(8);
}
}
return v;
}
}
I added a HashMap in which I save the selected items. I can call the select state from my activity, by calling the HashMap... And it works great!