By default, when you select an item in spinner, it highlights briefly before disappearing.
I changed the color of my spinner rows to alternate color with the following code, and the highlight disappears. R.layout.textviewinside and R.layout.textview don't cause this, just the #Override for getDropDownView, because everything works if I comment out that block.
How can I restore that functionality but keep the row colors?
products = new ArrayAdapter<String>(this, R.layout.textview, thedata){
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
View v = super.getDropDownView(position, convertView, parent);
if (position % 2 == 0) { // we're on an even row
v.setBackgroundColor(0xffEBF4FA);//Color.BLUE)
} else {
v.setBackgroundColor(Color.WHITE);
}
((TextView) v).setGravity(Gravity.CENTER);
return v;
}
};
products.setDropDownViewResource(R.layout.textviewinside);
spitem.setAdapter(products);
Instead of using setBackgroundColor, you'll need to use setBackgroundDrawable, and use an xml state list drawable file with pressed/default states.
http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList
Related
I'm using listview custom adapter which with row click i'm changing row color. But when i'm scrolling bot and up again it doesnt have the right position.
It changes color in other rows...
public override View GetView(int position, View convertView, ViewGroup parent)
{
DataViewHolder holder = null;
if (convertView == null)
{
convertView = LayoutInflater.From(mContext).Inflate(Resource.Layout.TableItems, null, false);
holder = new DataViewHolder();
holder.txtDescription = convertView.FindViewById<TextView>(Resource.Id.txtDescription);
holder.txtDescription.Click += delegate
{
holder.txtDescription.SetBackgroundColor(Color.Red);
};
convertView.Tag = holder;
}
else
{
holder = convertView.Tag as DataViewHolder;
}
holder.txtDescription.Text = mitems[position].Description;
return convertView;
}
public class DataViewHolder : Java.Lang.Object
{
public TextView txtDescription { get; set; }
}
It looks like it doesnt keep in memory specific row situation.
Don't change the color in the click handler directly, instead change the data from which the adapter draws from and use that to change the color when GetView is called again.
ListView recycles the views it uses to optimize scrolling, instead it just expects the view to represent the data. If you change a color of one view directly, the view then gets recycled and you'll see "another view" (another part of the data) with a different background color.
So in summary: give each data point a color attribute and use that to set the color of each view in GetView, change the data and notify the adapter about the changes to the data.
Edit
I've never used Xamarin but maybe something like this would work
public override View GetView(int position, View convertView, ViewGroup parent)
{
DataViewHolder holder = null;
if (convertView == null)
{
convertView = LayoutInflater.From(mContext).Inflate(Resource.Layout.TableItems, null, false);
holder = new DataViewHolder();
holder.txtDescription = convertView.FindViewById<TextView>(Resource.Id.txtDescription);
holder.txtDescription.Click += delegate
{
// instead of setting the color directly here, just modify the data
(holder.txtDescription.Tag as ItemType).ItemColor = Color.Red
notifyDataSetChanged();
};
convertView.Tag = holder;
}
else
{
holder = convertView.Tag as DataViewHolder;
}
holder.txtDescription.Text = mitems[position].Description;
holder.txtDescription.Tag = mitems[position]; // this so that the click handler knows which item to modify
holder.txtDescription.SetBackgroundColor(mitems[position].ItemColor);
return convertView;
}
public class DataViewHolder : Java.Lang.Object
{
public TextView txtDescription { get; set; }
}
ListView will reuse the item layout, you can use List and View.Tag to avoid the problem caused by reusing.
I have posted my demo on github.
ListView is generated from JSON with boolean getExpired.
if getExpired() is TRUE, then textColor should be changed.
but it set on list position even if == FALSE
Why 1st position is changed, if getExpired is FALSE on this item?
this is my getView
public View getView(int position, View convertView, ViewGroup parent) {
ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
if (item.getExpired()) {
vh.imageView.setColorFilter(filter);
vh.profilePhoto.setColorFilter(filter);
vh.expired.setVisibility(View.VISIBLE);
vh.username.setTextColor(Color.parseColor("#76808D"));
}
return vh.rootView;
}
If you're using the ViewHolder pattern you will be getting recycled views which have already have their views set to a certain state. In short, when using ViewHolder also use an else condition to set your view states how you want them to be.
My objective is to convert a working spinner (populated via a cursor adapter) to have alternating backgrounds. Similar to :-
Currently I have this, where everything works fine :-
This is the relevant working code within the cursor adpater (i.e. with the plain dropdowns) :-
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.activity_aisle_shop_list_selector, parent, false);
}
#Override
public void bindView(View view,Context context, Cursor cursor) {
determineViewBeingProcessed(view,"BindV",-1);
TextView shopname = (TextView) view.findViewById(R.id.aaslstv01);
shopname.setText(cursor.getString(shops_shopname_offset));
}
I have tried adding an override of the getDropDownView (code as below). I get the alternating row colors as I want but the dropdown views are blank. However, if I click outside of the selector, then they get populated with data (hence how I managed to get the screen shot, shown above, of what I want). Selection sets the correct Item.
If I remove the return after inflating the layout, then the dropdown views are populated but with data from other rows (however,selection selects the correct item)
public View getDropDownView(int position, View convertview, ViewGroup parent) {
View v = convertview;
determineViewBeingProcessed(v,"GetDDV",position);
if( v == null) {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_aisle_shop_list_entry, parent, false);
return v;
}
Context context = v.getContext();
TextView shopname = (TextView) v.findViewById(R.id.aasletv01);
shopname.setText(getCursor().getString(shops_shopname_offset));
if(position % 2 == 0) {
v.setBackgroundColor(ContextCompat.getColor(context,R.color.colorlistviewroweven));
} else {
v.setBackgroundColor(ContextCompat.getColor(context,R.color.colorlistviewrowodd));
}
return v;
}
The clues were they I just didn't think hard enough. The issue is with the cursor being in the wrong position because the cursor needs to be obtained via getCursor().
Additionally, the return after the inflate, is premature (this has been commented out).
Adding getCursor().moveToPosition(position); before accessing data from the cursor resolves the problem.
Alternately (perhaps more correctly, comments appreciated on whether or not one method is more correct than the other). Adding:-
Cursor cursor = getCursor();
cursor.moveToPosition(position);
and then replacing subsequent getCursor() with cursor (not mandatory) also works.
So the final code for getDropDownView method could be:-
public View getDropDownView(int position, View convertview, ViewGroup parent) {
View v = convertview;
determineViewBeingProcessed(v,"GetDDV",position);
if( v == null) {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_aisle_shop_list_entry, parent, false);
//return v;
}
Context context = v.getContext();
Cursor cursor = getCursor();
cursor.moveToPosition(position);
TextView shopname = (TextView) v.findViewById(R.id.aasletv01);
shopname.setText(cursor.getString(shops_shopname_offset));
if(position % 2 == 0) {
v.setBackgroundColor(ContextCompat.getColor(context,R.color.colorlistviewroweven));
} else {
v.setBackgroundColor(ContextCompat.getColor(context,R.color.colorlistviewrowodd));
}
return v;
}
I'm creating a custom adapter and using the getView method in attempt to display a default text only ONCE. Now I'm having a problem such that when I click the first Item in the list, the default text is kept but that doesn't hold for any other items? Any suggestions?
Thanks! (My code is a bit messy as I was just trying to debug)
boolean firstTime = true;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (firstTime) {
firstTime = false;
TextView firstView = new TextView(ForgotPasswordActivity.this);
firstView.setText("Please select School");
return firstView;
}
TextView view = new TextView(ForgotPasswordActivity.this);
view.setText("Hello");
return view;
}
You must play with the getCount function :
#Override
public int getCount() {
return super.getCount() -1; // This makes the trick;
}
this trick will not show last item that you've added inside your spinner(so when you finish adding your text inside the spinner, add the text that will not be shown in the spinner, and by that it will be show as a default value before clicking the spinner).
Good luck
I'm not exactly sure what your trying to do but you could force the top row to always show the select message by checking if the position is 0. Also notice in the code below that I'm reusing the convertView if it is not null. It's faster to reuse the convertView if it is available than to recreate a new view every time.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = new TextView(ForgotPasswordActivity.this);
}
if(position == 0) {
convertView.setText("Please select School");
} else {
convertView.setText("Hello");
}
return convertView;
}
Also remember that by forcing position zero to show the select message you are not showing the actual data in the adapter at position 0. Make sure this is what you want to do or insert a dummy piece of data in the first position of the backing data array.
I'm working on an application which will display some expandable lists. The fact is sometimes the object won't have any child. So I would like to display in my expandable list only elements which have childs.
I tried to put an if inside the getGroupView function and if the object has no child, I return null but I get a nullPointerException error...
Here is the function:
public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
// Check if the object as child
System.out.println("Result list :: " + mParent.get(i).getListe());
if(mParent.get(i).getListe().isEmpty()){
return null;
}
if (view == null) {
view = inflater.inflate(R.layout.list_item_parent, viewGroup,false);
}
TextView textView = (TextView) view.findViewById(R.id.list_item_text_view);
//"i" is the position of the parent/group in the list
textView.setText(getGroup(i).toString());
// Set the Image View with the brand logo
ImageView logo = (ImageView) view.findViewById(R.id.brandlogo);
// Set image Source
logo.setImageResource(mParent.get(i).getLogoPath());
// Set Image size
logo.getLayoutParams().height = 42;
logo.getLayoutParams().width = 226;
//return the entire view
return view;
}
Is there a way do skip this function?
Thanks
In getGroupCount() function return the number of items with childes (number of items has childes).
And in getGroubView() return the correct view (never return a null here).