Android: Change spinner items without closing the spinner - android

I am trying to implement a "More" button for a spinner. Basically I want to show only a few items at first and when the user clicks the last item ("More...") the spinner will change and show all items.
So the feature I need here, is a way to dynamically change spinner items without closing the spinner. I've managed to do everything but the last part. Every time I change the items the spinner automatically closes (without losing focus).
The only workaround I thought was to use mSpinner.performClick() to immediately open the spinner after it closes. Of course, that's not good enough because I get this quick close-reopen effect. Not cool.
I created a custom spinner class that manages the logic:
public class ReservationStatusSpinner extends Spinner {
// --------------------------------------------------
// State
// --------------------------------------------------
private final String mMoreStatus;
private OnItemSelectedListener mUserListener;
private ArrayAdapter<String> mAdapter;
private boolean mOpenInitiated = false;
// --------------------------------------------------
// Interfaces
// --------------------------------------------------
private interface OnSpinnerEventsListener {
// Not needed, but may be needed in the future -> void onSpinnerOpened();
void onSpinnerClosed();
}
private OnSpinnerEventsListener mOnSpinnerEventsListener;
public interface OnStatusSelectedListener {
void onStatusSelected(String status);
}
private OnStatusSelectedListener mOnStatusSelectedListener;
// --------------------------------------------------
// Construction/Initialization
// --------------------------------------------------
public ReservationStatusSpinner(Context context) {
super(context);
mMoreStatus = getContext().getResources().getString(R.string.status_more);
init();
}
public ReservationStatusSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
mMoreStatus = getContext().getResources().getString(R.string.status_more);
init();
}
private void init() {
// Add listener
super.setOnItemSelectedListener(new OnItemSelected());
mOnSpinnerEventsListener = new OnSpinnerEventsListener() {
#Override
public void onSpinnerClosed() {
filterAndSelect();
}
};
}
// --------------------------------------------------
// Overridden methods
// --------------------------------------------------
#Override
public boolean performClick() {
// register that the Spinner was opened so we have a status
// indicator for the activity(which may lose focus for some other
// reasons)
mOpenInitiated = true;
return super.performClick();
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
// mSpin is our custom Spinner
if (mOpenInitiated && hasFocus) {
performClosedEvent();
}
}
#Override
public void setOnItemSelectedListener(OnItemSelectedListener l) {
mUserListener = l;
}
// --------------------------------------------------
// Private methods
// --------------------------------------------------
private static ArrayList<String> getAllStatuses(Context context) {
ArrayList<String> items = new ArrayList<>();
CharSequence[] statusesCSArray = context.getResources().getTextArray(R.array.reservation_status);
for (CharSequence cs : statusesCSArray)
items.add(cs.toString());
return items;
}
private void performClosedEvent() {
mOpenInitiated = false;
if (mOnSpinnerEventsListener != null) {
mOnSpinnerEventsListener.onSpinnerClosed();
}
}
private void filterAndSelect() {
List<String> items = filterStatuses((String)getSelectedItem(), mMoreStatus);
setItems(items);
setSelection(0);
}
// --------------------------------------------------
// Public methods
// --------------------------------------------------
public void setStatus(String status) {
// Find status in adapter
int pos = -1;
for (int i = 0; i < mAdapter.getCount(); ++i) {
if (mAdapter.getItem(i).equals(status)) {
pos = i;
break;
}
}
if (pos != -1)
setSelection(pos);
}
public void setAdapter(ArrayAdapter<String> adapter) {
super.setAdapter(adapter);
mAdapter = adapter;
}
public void setOnStatusSelectedListener(OnStatusSelectedListener l) {
mOnStatusSelectedListener = l;
}
public void setItems(List<String> items) {
mAdapter.clear();
mAdapter.addAll(items);
mAdapter.notifyDataSetChanged();
}
// --------------------------------------------------
// Utilities
// --------------------------------------------------
public static ArrayList<String> filterStatuses(String selectedStatus, String moreStatus) {
ArrayList<String> list = new ArrayList<>(DataUtilities.filterStatuses(selectedStatus));
// Add selected status at start
list.add(0, selectedStatus);
// Append "More"
list.add(moreStatus);
return list;
}
// --------------------------------------------------
// Custom ItemSelectedListener for ReservationStatusSpinner
// --------------------------------------------------
private class OnItemSelected implements OnItemSelectedListener {
private String mPreviousStatus;
private boolean mMoreClicked = false;
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String more = getContext().getResources().getString(R.string.status_more);
String status = getSelectedItem().toString();
ArrayList<String> items = new ArrayList<>();
if (status.equals(more)) {
items.addAll(getAllStatuses(getContext()));
items.remove(mMoreStatus);
setItems(items);
//setStatus(mPreviousStatus);
mMoreClicked = true;
// Reopen spinner (it closes after changing data) (TODO: Fix this)
ReservationStatusSpinner.this.performClick();
} else if (!mMoreClicked) {
filterAndSelect();
}
if (!status.equals(more)) {
if (mUserListener != null)
mUserListener.onItemSelected(parent, view, position, id);
if (mOnStatusSelectedListener != null)
mOnStatusSelectedListener.onStatusSelected(status);
}
mPreviousStatus = status;
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
if (mUserListener != null)
mUserListener.onNothingSelected(parent);
}
}
}
and a custom adapter:
public class ImageSpinnerAdapter extends ArrayAdapter<String> {
private LayoutInflater mInflater;
public ImageSpinnerAdapter(Context context, int textViewResourceId, List<String> titles) {
super(context, textViewResourceId, titles);
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getDropDownView(int position, View convertView, #NonNull ViewGroup parent) {
View view;
if (convertView == null) {
view = mInflater.inflate(R.layout.row_image_spinner_dropdown, parent, false);
} else {
view = convertView;
}
ImageView icon = (ImageView)view.findViewById(R.id.spinner_icon);
setIcon(icon, getItem(position));
TextView text = (TextView)view.findViewById(R.id.spinner_status_text);
text.setText(DataUtilities.addWhitespacesToStatus(getItem(position)));
view.setPadding(0, 0, 0, 0);
return view;
}
#NonNull
#Override
public View getView(int position, View convertView, #NonNull ViewGroup parent) {
View view;
if (convertView == null) {
view = mInflater.inflate(R.layout.row_image_spinner_view, parent, false);
} else {
view = convertView;
}
// Set icon
ImageView icon = (ImageView)view.findViewById(R.id.spinner_icon);
setIcon(icon, getItem(position));
view.setPadding(0, 0, 0, 0);
return view;
}
private void setIcon(ImageView icon, String status) {
// Make sure there are no whitespaces in status
status = DataUtilities.removeWhitespaceFromStatus(status);
// Get the correct image for each status
icon.setImageResource(DataUtilities.statusToIconResource(status));
}
}
In my Spinner, most of the work is done in the private class OnItemSelected at the end of the snippet.
At first I thought the problem was the convert view at my adapter (I wasn't using the convert view pattern at first) but as you can see I'm using it now.
The problem occurs on 2 different devices and my emulator so it's safe to assume that it is not a device specific problem.
Anyone have any ideas or any pointers?

You have to create custom dialog with MultiSelectListview and More button.On click of more button you have to add all elements to Listview and call notifyDataSetChanged() method.

Default Spinner can't simple way to load "More" items. But "More" button has no sense. If you have 30-50 items just load all to Spinner. For 50-150 items use own ListBox/RecyclerView based Spinner. If more 150 items user too hard search necessary one item. In last case useful to add "Search" functionality.
See MultiSelect Spinner for ideas.

Related

Fragment ListView Inflation of new Row to Maintain onItemClick Selection

I have a ListView that is within a Fragment. In the onCreateView section I have set a onItemClickListener for the list, which highlights the selected item in the ListView. I have set two ImageButtons that navigate up and down the list. On selection a new Row is inflated that has its TextView's set to the content of the select item (for the purpose of retaining the highlighted selected state). However I am having difficulty adding that item back to the list. The app will not compile due to the line routines.add(selectedPos-1, str); it wants wants int location, Routine object. I believe the issue is with my construction of my SelectedAdapter class, but I have been unable to determine what to change/pass with regard to the Object.
IE:
public SelectedAdapter(Context context, int textViewResourceId,List objects) {
super(getActivity(), R.layout.listview_routines, routines); }
I would greatly appreciate any input as how to correct this issue; as well as any advice if there is a better way to maintain a selected state. Thanks for your help.
Fragment:
public static class FragmentRoutine extends Fragment {
DatabaseHandler db;
private ListView routineListView;
private List<Routine> routines = new ArrayList<Routine>();
ArrayAdapter<Routine> routineAdapter;
Routine longClickedItemRoutines;
private SelectedAdapter selectedAdapter;
public FragmentRoutine() {}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.routines,
container, false);
db = new DatabaseHandler(getActivity().getApplicationContext());
routineListView = (ListView) rootView.findViewById(R.id.routineList);
registerForContextMenu(routineListView);
db.closeDB();
if (db.getExerciseCount() != 0)
routines.clear();
routines.addAll(db.getAllRoutines());
populateList();
selectedAdapter = new SelectedAdapter(this.getActivity(), 0, routines);
selectedAdapter.setNotifyOnChange(true);
routineListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
longClickedItemRoutines = routines.get(position);
return false;
}
});
routineListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView arg0, View view,
int position, long id) {
selectedAdapter.setSelectedPosition(position);
}
});
routineListView.post(new Runnable() {
#Override
public void run() {
routineListView.setItemChecked(0, true);
}
});
// move up event handler
ImageButton btnMoveUp = (ImageButton) rootView.findViewById(R.id.btnMoveUp);
btnMoveUp.setOnClickListener(new AdapterView.OnClickListener() {
public void onClick(View arg0) {
moveUp();
}
});
// move down event handler
ImageButton btnMoveDown = (ImageButton) rootView.findViewById(R.id.btnMoveDown);
btnMoveDown.setOnClickListener(new AdapterView.OnClickListener() {
public void onClick(View arg0) {
moveDown();
}
});
setHasOptionsMenu(true);
return rootView;
}
// Move selected item "up" in the ViewList.
private void moveUp(){
Routine currentToDoSave = routines.get(selectedAdapter.getSelectedPosition());
int selectedPos = selectedAdapter.getSelectedPosition();
if (selectedPos > 0 ){
routines.remove(selectedPos);
String str = currentToDoSave.getTagName();
//Problem Line Below
routines.add(selectedPos-1, str);
// set selected position in the adapter
selectedAdapter.setSelectedPosition(selectedPos-1);
}
}
// Move selected item "down" in the ViewList.
private void moveDown(){
Routine currentToDoSave = routines.get(selectedAdapter.getSelectedPosition());
int selectedPos = selectedAdapter.getSelectedPosition();
if (selectedPos < routines.size()-1 ){
routines.remove(selectedPos);
String str = currentToDoSave.getTagName();
routines.add(selectedPos+1, str);
// set selected position in the adapter
selectedAdapter.setSelectedPosition(selectedPos+1);
}
}
public class SelectedAdapter extends ArrayAdapter<Routine>{
// used to keep selected position in ListView
private int selectedPos = -1; // init value for not-selected
public SelectedAdapter(Context context, int textViewResourceId,
List objects) {
super(getActivity(), R.layout.listview_routines, routines);
}
public void setSelectedPosition(int pos){
selectedPos = pos;
// inform the view of this change
notifyDataSetChanged();
}
public int getSelectedPosition(){
return selectedPos;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
// only inflate the view if it's null
if (v == null) {
LayoutInflater vi
= (LayoutInflater)this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.selected_row, null);
}
// get text view
TextView label = (TextView)v.findViewById(R.id.txtExample);
// change the row color based on selected state
if(selectedPos == position){
label.setBackgroundColor(Color.CYAN);
}else{
label.setBackgroundColor(Color.WHITE);
}
label.setText(this.getItem(position).toString());
return(v);
}
}
private void populateList() {
routineAdapter = new SaveListAdapterT();
routineListView.setAdapter(routineAdapter);
}
public class SaveListAdapterT extends ArrayAdapter<Routine> {
public SaveListAdapterT() {
super(getActivity(), R.layout.listview_routines, routines);
}
#Override
public View getView(int position, View view, ViewGroup parent) {
if (view == null)
view = getActivity().getLayoutInflater().inflate(R.layout.listview_routines, parent, false);
Routine currentToDoSave = routines.get(position);
TextView name = (TextView) view.findViewById(R.id.name);
name.setText(currentToDoSave.getTagName());
return view;
}
}
}

Multiselect listView with ActionMode - how to keep selected items?

I'm trying to create ListView with installed apps. User selects apps inside wizard (basically viewpager).
My plan is to create a list of custom views (icon, name, package) that will allow to select more than one item. Unfortunatelly checkboxes won't work, because I need this place for another functionality. So, I'll change the background of the element.
So, I found a solution on stackoverflow and changed it a bit.
Firstly - main activity with this list.
public class MainActivity extends ListActivity {
private static final String TAG = MainActivity.class.getName();
private ApplicationsAdapter applicationsAdapter;
private void getAppList(){
//get apps asynch
createList(list);
}
private void createList(ArrayList<ApplicationItem> list){
applicationsAdapter = new ApplicationsAdapter(this, R.layout.application_list_item, list);
setListAdapter(applicationsAdapter);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
getListView().setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
private int nr = 0;
#Override
public boolean onCreateActionMode(android.view.ActionMode mode, Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.cabselection_menu, menu);
return true;
}
#Override
public boolean onPrepareActionMode(android.view.ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(android.view.ActionMode mode, MenuItem item) {
return false;
}
#Override
public void onDestroyActionMode(android.view.ActionMode mode) {
nr = 0;
applicationsAdapter.clearSelection();
}
#Override
public void onItemCheckedStateChanged(android.view.ActionMode mode, int position, long id, boolean checked) {
if (checked) {
nr++;
applicationsAdapter.setNewSelection(position, checked);
L.d(TAG, applicationsAdapter.getItem(position).getAppName());
} else {
nr--;
applicationsAdapter.removeSelection(position);
}
mode.setTitle(nr + " rows selected!");
}
});
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getAppList();
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
ApplicationItem item = (ApplicationItem)l.getAdapter().getItem(position);
L.d(TAG + "onListItemClick", applicationsAdapter.getItem(position).getAppName());
l.setItemChecked(position, !applicationsAdapter.isPositionChecked(position));
}
}
In my case, normally this whole thing is inside a fragment, inside the viewpager. For the sake of clarity I changed this into typical activity.
Now, the adapter:
public class ApplicationsAdapter extends ArrayAdapter<ApplicationItem> {
// private HashMap<ApplicationItem, Boolean> objects;
private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();
public ApplicationsAdapter(Context context, int textViewResourceId, ArrayList<ApplicationItem> objects) {
super(context, textViewResourceId, objects);
//this.objects = objects;
}
public void setNewSelection(int position, boolean value) {
mSelection.put(position, value);
notifyDataSetChanged();
}
public boolean isPositionChecked(int position) {
Boolean result = mSelection.get(position);
return result == null ? false : result;
}
public Set<Integer> getCurrentCheckedPosition() {
return mSelection.keySet();
}
public void removeSelection(int position) {
mSelection.remove(position);
notifyDataSetChanged();
}
public void clearSelection() {
mSelection = new HashMap<Integer, Boolean>();
notifyDataSetChanged();
}
public ApplicationItem getItem(int position){
return super.getItem(position);
}
public View getView(int position, View convertView, ViewGroup parent){
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.application_list_item, null);
}
ApplicationItem item = super.getItem(position);
if(item != null){
TextView appName = (TextView) v.findViewById(R.id.appName);
TextView appPackage = (TextView) v.findViewById(R.id.appPackage);
ImageView appIcon = (ImageView) v.findViewById(R.id.appIcon);
if (appName != null){
appName.setText(item.getAppName());
}
if (appPackage != null){
appPackage.setText(item.getPackageName());
}
if (appIcon != null){
appIcon.setImageDrawable(item.getIcon());
}
}
v.setBackgroundColor(Color.parseColor("#00FFFFFF")); //default color
if (mSelection.get(position) != null) {
v.setBackgroundColor(Color.BLUE);// this is a selected position so make it red
}
return v;
}
}
THE PROBLEM:
ActionMode is nice, however I'm not sure how to keep selected elements after it's destroy.
Normally inside onDestroyActionMode I'm clearing the selection. Great, so I'll just delete that. Now after clicking the "tick" symbol all apps are still selected. However, getting back to them is now problematic, because ActionMode will only "fire up" when clicking on unselected element.
So - how should I handle that?
Ha, the answer was quite simple. I should have thought about it yesterday, but apparently I was a bit too exhausted.
First of all, I changed the mode of listview into
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
And deleted setMultiChoiceModeListener() and I'm only using
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
ApplicationItem item = (ApplicationItem)l.getAdapter().getItem(position);
L.d(TAG + "onListItemClick", applicationsAdapter.getItem(position).getAppName());
boolean checked = item.isSelected();
if (!checked) {
item.setSelected(true);
applicationsAdapter.setNewSelection(position, checked);
L.d(TAG, applicationsAdapter.getItem(position).getAppName());
} else {
item.setSelected(false);
applicationsAdapter.removeSelection(position);
}
}
That simple.
Apparently, ActionMode may be fun, but it wasn't the right tool for this job.
And also - adapter from first post can be used as a example of multiselect listView that changes backgrounds instead of checkboxes. Apparently I couldn't find anything simple enough like that.

Listviews with EditText behavior

i've noticed an extrage behavior on my app that has a ListView with three EditTexts,
the problem is that whenever i select one textedit and move away from focus and come back the text i wrote in the first row i selected either desapears or moves to a different row, also when an edittext is focused and i go down in the list it seems that i have selected the edittext in the same position but 10 or 11 rows after the one im actually focusing(the one i can write to).
any knowledge on that case?
also im new to android so i dont know if thats supposed to happen.
this is the List im using.
public class In_List {
private int id;
private String text;
private float a;
private float Qty;
public In_List (int id, String text, float a, float Qty) {
this.id = id;
this.text = text;
this.a = a;
this.Qty= Qty;
}
public String get_text() {
return text;
}
public float get_a() {
return a;
}
public int get_id() {
return id;
}
public float get_Qty() {
return Qty;
}
}
here is the adapter:
public abstract class List_Adapter extends BaseAdapter {
private ArrayList<?> ins;
private int R_layout_IdView;
private Context context;
public Lista_adaptador(Context context, int R_layout_IdView, ArrayList<?> ins) {
super();
this.context = context;
this.ins = ins;
this.R_layout_IdView = R_layout_IdView;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
if (view == null) {
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = vi.inflate(R_layout_IdView, null);
}
onInsert (ins.get(position), view);
return view;
}
#Override
public int getCount() {
return ins.size();
}
#Override
public Object getItem(int position) {
return ins.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public abstract void onInsert (Object insert, View view);
}
and here is the main activity. it has a popup window that i used to fill the value of Qty but i its not included.
public class MainActivity extends Activity {
private ListView list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listing);
ArrayList<In_List> data = new ArrayList<>();
for(int i=0; i<100; i++){
data.add(new In_List(i, "Item Number :"+i+1, i*2,0));
}
list = (ListView) findViewById(R.id.ListView_listing);
list.setAdapter(new List_Adapter(this, R.layout.entry, data){
#Override
public void onInsert(Object entr, View view) {
if (entr != null) {
TextView id_Text = (TextView) view.findViewById(R.id.textView_id);
if (id_Text != null)
id_Text.setText(((In_List) entr).get_id());
TextView info_Text = (TextView) view.findViewById(R.id.textView_info);
if (info_Text != null)
info_Text.setText(((In_List) entr).get_text());
TextView inside_Text = (TextView) view.findViewById(R.id.textView_inside);
if (inside_Text != null)
inside_Text.setText(((In_List) entr).get_a());
TextView Qty_Text = (TextView) view.findViewById(R.id.textView_qty);
if (Qty_Text != null || Qty_Text.getText().toString().equals(0))
Qty_Text.setText(((In_List) entr).get_Qty());
Qty_Text.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Add_Qty();
}
});
}
}
});
// list.setOnItemClickListener(new OnItemClickListener() {
// #Override
// public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// In_List chosen = (In_List) parent.getItemAtPosition(position);
//
// CharSequence text = "Selected: " + chosen.get_textoDebajo();
// Toast toast = Toast.makeText(MainActivity.this, texto, Toast.LENGTH_LONG);
// toast.show();
// }
// });
}
}
now, when i scroll down through the list the Qtys that i have entered either disappear or move to another row.
fixed. i wasn't stablishing Qty_Text value at all. also made a method to save into the adapter array.
EditTexts in generally are very tricky. And using them inside a ListView is almost impossible. The special behaviour of EditTexts for example to always automatically assume focus combinded with the View recycling of the ListViews messes with the ListView and causes a lot of problems. I would suggest you look for another solution. For example placing the EditText inside the HeaderView of the ListView is fine, as the HeaderView is not recycled as you scroll through the ListView.

Change the Background of Select/Click listview Item - Android

I am working on the quiz application.For that I am using listview for the dispaly the answers options, I want to change the listview background color when user select the listview item, If answer is correct then set the green background and wrong then set red background
I am tring so much, but i don,t get the solution.
Adapter class
public class ListviewAdapter extends BaseAdapter{
public List<String> Questions;
public Activity context;
public LayoutInflater inflater;
private int[] colors = new int[] { 0x30505050, 0x30808080 };
private String[] opt_no;
public static View change_color;
public ListviewAdapter(Activity context,List<String> answers, String[] que_opt_no) {
super();
this.context = context;
this.Questions = answers;
this.opt_no = que_opt_no;
//this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return Questions.size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return Questions.get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
public static class ViewHolder
{
TextView txtquestion;
TextView txtquestion_no;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder;
LayoutInflater inflater = context.getLayoutInflater();
// this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
String fontPath = "fonts/Face Your Fears.ttf";
if(convertView==null)
{
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.quiz_questions_listitem, null);
holder.txtquestion = (TextView) convertView.findViewById(R.id.textView_option);
holder.txtquestion_no = (TextView) convertView.findViewById(R.id.textView_option_no);
// holder.txtquestion .setTypeface(Typeface.createFromAsset(convertView.getContext().getAssets(),fontPath));
convertView.setTag(holder);
}
else
holder=(ViewHolder)convertView.getTag();
/* int colorPos = position % colors.length;
convertView.setBackgroundColor(colors[colorPos]); */
change_color = convertView;
// convertView.setBackgroundResource(R.drawable.listview_background);
holder.txtquestion.setText(Questions.get(position));
holder.txtquestion_no.setText(opt_no[position]);
return convertView;
}
/*public static void setbackground(){
String answer = SelectedAnswer.getAnswer();
if (Display_questions.currentQ.getAnswer().trim().equals(answer.trim()))
{
Toast.makeText(change_color.getContext(), "red",Toast.LENGTH_SHORT).show();
change_color.setBackgroundResource(R.drawable.listview_background);
//ListviewAdapter.change_color.setBackgroundResource(R.drawable.listview_background);
//Display_questions.currentGame.incrementRightAnswers();
}
else{
Toast.makeText(change_color.getContext(), "Blue",Toast.LENGTH_SHORT).show();
change_color.setBackgroundResource(R.drawable.listview_false_background);
//Display_questions.currentGame.incrementWrongAnswers();
}
}*/
}
Java class
public class Display_questions extends Activity{
public static Question currentQ;
public static GamePlay currentGame;
ListView listview;
ListviewAdapter adapter;
String que_opt_no[] = {"a) ","b)","c) ","d) "};
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.quiz_questions);
listview = (ListView) findViewById(R.id.questions_list);
listview.setItemsCanFocus(false);
GoToNextQuestion();
}
private void GoToNextQuestion() {
// TODO Auto-generated method stub
listview.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> myAdapter, View myView, int pos, long mylng) {
String selectedFromList = (String) listview.getItemAtPosition(pos);
SelectedAnswer.setAnswer(selectedFromList);
if (!checkAnswer(pos)) return;
if (currentGame.isGameOver()){
Intent i = new Intent(Display_questions.this, Display_result.class);
i.putExtra("Timer_Value", TimerTime);
startActivity(i);
finish();
}
else{
GoToNextQuestion();
}
}
});
setQuestions();
}
private void setQuestions() {
// set the question text from current question
String question = currentQ.getQuestion().trim();
TextView qText = (TextView) findViewById(R.id.txt_questions);
qText.setText(question);
// set the available options
List<String> answers = currentQ.getQuestionOptions();
adapter = new ListviewAdapter(this,answers,que_opt_no);
listview.setAdapter(adapter);
}
static boolean checkAnswer(int selectedPosition) {
String answer = SelectedAnswer.getAnswer();
if (answer==null){
return false;
}
else {
AnswerStates state = AnswerStates.NONE;
if (currentQ.getAnswer().trim().equals(answer.trim()))
{
//listview.setBackgroundResource(R.drawable.listview_background);
currentGame.incrementRightAnswers();
state = AnswerStates.RIGHT;
}
else{
//ListviewAdapter.setbackground();
currentGame.incrementWrongAnswers();
state = AnswerStates.WRONG;
}
adapter.setSelectedAnswerState(selectedPosition, state);
adapter.notifyDataSetChanged();
return true;
}
}
}
Edit :
check My images :
1.)
2.)
Do you want to change the background of listview or the selected item when a correct answer is selected.
#Override
public void onItemClick(AdapterView<?> myAdapter, View myView, int pos, long mylng) {
String selectedFromList = (String) listview.getItemAtPosition(pos);
if(selectedFromList.equals("your_answer")) {
// to change the listview background
listview.setBackgroundColor(getResources().getColor(R.color.your_color_id));
// to change the selected item background color
myView.setBackgroundColor(getResources().getColor(R.color.your_color_id));
}
I would suggest to go with the following way:
Adapter class:
add storing of selected position and its state (CORRECT/INCORRECT) or color, e.g.:
public class ListviewAdapter extends BaseAdapter{
enum AnswerStates {
// Colors can be provided also for bg
WRONG(R.drawable.wrong_bg),
RIGHT(R.drawable.right_bg),
NONE(R.drawable.list_item_bg);
/** Drawable id to be used for answer state */
private int mBg;
private AnswerStates(int bg) {
mBg = bg;
}
/** getter for drawabale for answer state */
int getBg() {
return mBg;
}
}
...
/** Position of selected answer */
private int mSelectedPosition = -1;
/** State of selected answer */
private AnswerStates mSelectedAnswerState = AnswerStates.NONE;
...
/** Setter for selected answer */
public void setSelectedAnswerState(int selectedPosition, AnswerStates state) {
mSelectedPosition = selectedPosition;
mSelectedAnswerState = state;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
...
// Your stuff
...
if (position == mSelectedPosition) {
convertView.setBackgroundResource(mSelectedAnswerState.getBg());
} else {
// use default bg
convertView.setBackgroundResource(AnswerStates.NONE.getBg());
}
return convertView;
}
...
}
And Activity class:
public class Display_questions extends Activity{
...
// Added position parameter to the function
static boolean checkAnswer(int selectedPosition) {
//getSelectedAnswer();
String answer = SelectedAnswer.getAnswer();
if (answer==null){
return false;
}
else {
AnswerStates state = AnswerStates.NONE;
if (currentQ.getAnswer().trim().equals(answer.trim()))
{
// here set the background Green color
currentGame.incrementRightAnswers();
state = AnswerStates.RIGHT;
}
else{
// here set the background red color
//ListviewAdapter.setbackground();
currentGame.incrementWrongAnswers();
state = AnswerStates.WRONG;
}
adapter.setSelectedAnswerState(selectedPosition, state);
adapter.notifyDataSetChanged();
return true;
}
}
}
This way is more reliable than another answer, because it will work even if list with answers get scrolled and views get reused by list view.

ListView and List Adapter in android change color

I have a list activity which has a list showing results of a query. Well I want to be able to click on each item and the item changes color but it doesn't work. I want the item to remain selecetd state untill "accepte" button is pressed or item is pressed again. I know that is how text boxes work but i prefer to do it my own way.
Here is my code:
public void createList() {
if (ok == 1) {
//hay muachas possibilidades
if (sol.get(i).getMultiseleccion() != 0){
bt2.setVisibility(View.INVISIBLE);
}else {
//solo se clika en una
//lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
bt2.setVisibility(View.VISIBLE);
}
String hd1 = sol.get(i).getDescSolicitud();
tv2.setText(hd1);
ArrayList<SubSolicitud> sub = sol.get(i).getSubSol();
mAdapter = new EventAdapter(this, sub);
setListAdapter(mAdapter);
lv.setTextFilterEnabled(true);
lv.computeScroll();
lv.setDividerHeight(1);
lv.setItemsCanFocus(false);
lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long arg3) {
ok = 1;
//OnListClick(position, arg1);
if (sol.get(i).getMultiseleccion() != 0) {
// multiples respuestas
((EventEntryView)arg1).text1.setTextColor(Color.YELLOW);
guardarRespuesta();
}else {
buscarElementos();
}
}
});
}
// informar el usuario de que hay un error
else
buildAlertDialog();
}
and the other classes are:
public class EventAdapter extends BaseAdapter {
public ArrayList<SubSolicitud> mEvents = null;
public EventAdapter(Context c, ArrayList<SubSolicitud> subsol) {
mContext = c;
mEvents = subsol;
}
public int getCount() {
return mEvents.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
EventEntryView btv;
if (convertView == null) {
btv = new EventEntryView(mContext, mEvents.get(position));
} else {
btv = (EventEntryView) convertView;
String title1 = mEvents.get(position).getDescripcion();
if (title1 != null) {
btv.setText1Title(title1);
}
}
btv.setBackgroundColor(Color.BLACK);
return btv;
}
private Context mContext;
public void clearEvents() {
mEvents.clear();
notifyDataSetChanged();
}
public void addEvent(SubSolicitud e) {
mEvents.add(e);
}
}
public class EventEntryView extends LinearLayout {
// private View inflatedView;
private TextView text1;
// private TextView text2;
public EventEntryView(Context context, SubSolicitud subSolicitud) {
super(context);
this.setOrientation(VERTICAL);
text1=new TextView(context);
text1.setTextSize(20);
text1.setPadding(10, 10, 10, 10);
text1.setTextColor(Color.WHITE);
String t = subSolicitud.getDescripcion();
text1.setText(t);
addView(text1, new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
public void setText1Title(String title1) {
// TODO Auto-generated method stub
text1.setText(title1);
}
}
As you can see I try to get the text in yellow but it doesn't work I click and it doesn't become yellow.
Is there a solution?
thanks
It doesn't work because there is not an EventEntryView for each item in the list - the same EventEntryView is reused to render each.
You need to add something on your SubSolicitud model object to indicate it's been selected (let's say a boolean "selected" property).
In your onItemClicked handler you would toggle this property -
public void onItemClick(AdapterView<?> adapterView, View view,
int position, long id) {
// ...
SubSolicitud selectedSubSol = (SubSolicitud)adapterView.getAdapter().getItem(id);
boolean currentValue = selectedSubSol.isSelected();
selectedSubSol.setSelected(!currentValue); // toggle 'selected' on and off
// ...
}
(You also need to fix your EventAdapter getItem method to return mEvents.get(position) for this to work...)
Then in your EventAdapter getView method, you use the value of the "selected" property to render the text color -
public View getView(int position, View convertView, ViewGroup parent) {
// ...
if (mEvents.get(position).isSelected()) {
btv.text1.setTextColor(Color.YELLOW);
} else {
// you have to have an else to set it back to the default
// color, because the view is reused for all list items.
btv.text1.setTextColor(Color.WHITE);
}
// ...
}
This is how you change the color.
public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long arg3) {
position = position - listView.getFirstVisibleItem();
((EditText)arg0.getChildAt(position).findViewById(R.id.myTextView)).setTextColor(Color.YELLOW);
}
But if you want to release the item from the color you should iterate through each item of the listview and change it back to normal or you can do it inside the getView() since it is called every time there is action on the listview

Categories

Resources