Aligning Selected Spinner Item - android

I'm trying to make a slight adjustment to the positioning of the selected item in the spinner. Not the dropdown list items, as I already have a custom view in my adapter for that, but the selected item specifically.
As you can see in the screenshot, "Any" is the currently selected item. But it is aligned oddly within the container because it has to accommodate the longest string in the dropdown, which is "Dark Purple Burnt Sienna" (or whatever). I want to align the selected text to the right so that "Any" is next to the dropdown indicator instead of way out in the middle.
I've attempted to make adjustments to my custom spinner-item view, but it doesn't have any affect on the selected item.
I've also attempted to set gravity and text alignment on the Spinner itself, but it has no effect.
Here's the image and the xml:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/default_black"
android:layout_centerVertical="true"
android:text="Color" />
<Spinner
android:id="#+id/spn_color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"/>
</RelativeLayout>
Edit: Here's my adapter:
public class ColorsAdapter<T> implements SpinnerAdapter {
ArrayList<String> mColors;
ArrayList<Integer> mValues;
Context mContext;
public ColorsAdapter(ArrayList<String> colors, ArrayList<Integer> values,
Context context) {
mContext = context;
mColors = colors;
mValues = values;
}
#Override
public int getCount() {
return mColors.size();
}
#Override
public Object getItem(int position) {
return mColors.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return R.layout.list_item_color;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView v = new TextView(mContext);
v.setText(mColors.get(position));
return v;
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE );
View row = inflater.inflate(getItemViewType(position), parent, false);
TextView tvName = (TextView)row.findViewById(R.id.tv_name);
tvName.setText(mColors.get(position));
row.setTag(mValues.get(position));
return row;
}
#Override
public int getViewTypeCount() {
return 1;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isEmpty() {
return false;
}
}
And here's the XML for the list item:
<TextView
android:id="#+id/tv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:gravity="right"/>

You can adjust the settings for selected item in getView(int position, View convertView, ViewGroup parent) method. If you just want to set the gravity and text alignment, you should set it to the TextView in the method like
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView v = new TextView(mContext);
v.setText(mColors.get(position));
v.setGravity(Gravity.END); // OR v.setGravity(Gravity.RIGHT);
return v;
}
Or you can simply inflate custom layout if you want to make further customization:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
View row = null;
if (inflater != null) {
row = inflater.inflate(R.layout.list_item_view_color, parent, false);
TextView textView = row.findViewById(R.id.textview);
textView .setText(mColors.get(position));
}
return row;
}
Where list_item_view_color.xml is your layout file for the selected value.
(NOTE: If you want to use options like autoSizeTextType, you can use them with app prefix for AppCompatTextView in xml files)

Simple solution would be to build another Custom view for the spinner TextView layout, and specify the gravity for your TextView in that. Something like :
<!--spinner_layout.xml (in layout/)-->
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
/>
Use that in initalising the ArrayAdapter of your spinner :
ArrayAdapter<String> adapter = new ArrayAdapter<String>
(this, android.R.layout.spinner_layout,
spinnerArray);
UI output :

You can creating the TextView for the getView method programmatically so no property for alignment is being set, easy thing to do is inflate it in the same way you are doing it on the getDropdownView, or simply set the proper gravity in the view you are instantiated.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView v = new TextView(mContext);
v.setText(mColors.get(position));
v.setGravity(Gravity.RIGHT);
return v;
}

You can try this
android:autoSizeTextType="uniform"

Padding, Margins and Alignments get confusing when it comes to Spinners. I ran into a similar issue as well. But for me I wasn't using a custom view and adapter, so I managed to use styles to get around this issue.
For you since you are already using custom view and adapter, you can make the background null for the spinner so that the dropdown arrow will not be visible.
android:background="#null"
Then in the TextView, you can assign drawableRight to be the dropdown arrow.
android:drawableRight="#drawable/ic_spinner_drop_arrow_white_24dp"
The icon can be a dropdown vector drawable. Also to specify particular margin between the arrow and text, you should be able to use drawablePadding
Hope this helps.

I can give you a method that may work.
In XML
1) add a new text view called the_current_color text view
2) allign this text view above the spinner and to the start of the arrow icon
or wherever you want it to be.
In your code
1) when you listen to (on item selected ) from the spinner simply get the current text and set it in the (the_current_color) text view.
2) and try to hide the texts in the spinner by changing color to transparent.
Hope it works
Edit
I might also suggest something maybe it changes things
lets say that we have a spinner that uses this string resource file to populate its adapter
<string-array name="my_adapter">
<item>Blue </item>
<item>Red</item>
</string-array>
until now we have a spinner that shows (red item) and (blue item) at the far left from the arrow icon of the spinner.
create another string resources now like that
<string-array name="my_adapter_two">
<item> Blue </item>
<item> Red</item>
</string-array>
as you can see now the added space will give an illusion that the strings are beside the arrow icon
you can add space that fit your need and you can maybe switch the files after you click a certain item and then switch them back.

You can try the following Custom view.
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/textView1"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="right"
android:padding="15dp"
android:textAlignment="gravity"
android:textColor="#color/black"
android:textSize="10dp" />

Related

Android custom ArrayAdapter rendering Objects in list, not values

I'm trying to bind a custom layout (a LinearLayout containing two TextViews) to a Spinner. I subclassed ArrayAdapter (mostly) correctly. Selecting an item in the Spinner calls getView() correctly, setting the LinearLayout's TextViews' values correctly. The problem is the initial display of the items in the Spinner (when clicking on the Spinner) just shows Objects; not the TextViews they should be displaying. Only AFTER clicking on one of the Objects does the Spinner correctly set the TextViews using my custom adapter's getView() method. Here's the custom adapter class:
public class BusRouteAdapter extends ArrayAdapter<BusRoute> {
...
public BusRouteAdapter(Context context, int resource, int textViewId, ArrayList<BusRoute> routes) {
super(context, resource, textViewId, routes);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
BusRoute route = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.bus_route, parent, false);
}
TextView tvBusRoute = (TextView) convertView.findViewById(R.id.tvBusRoute);
TextView tvBusRouteNumber = (TextView) convertView.findViewById(R.id.tvBusRouteNumber);
tvBusRoute.setText(route.routeName);
tvBusRoute.setTag(route.route);
tvBusRouteNumber.setText(route.route);
if (!route.routeColor.equals("")) {
tvBusRouteNumber.setBackgroundColor(Color.parseColor(route.routeColor));
}
return convertView;
}
}
Here's the layout that is to be used for each Spinner list item (bus_route.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1">
<TextView
android:id="#+id/tvBusRouteNumber"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.25"
android:padding="8dp" />
<TextView
android:id="#+id/tvBusRoute"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.75"
android:padding="8dp" />
</LinearLayout>
And in my Activity, I'm setting the adapter to a properly-populated list of BusRoute objects:
busRouteAdapter = new BusRouteAdapter(getBaseContext(), R.layout.bus_route, R.id.tvBusRoute, arrayOfBusRoutes);
routesSpinner.setAdapter(busRouteAdapter);
It does seem strange that I need to pass the Layout id (R.layout.bus_route) AND one of the TextViews contained in that Layout (R.id.tvBusRoute).
Here's what is rendered when clicking on the Spinner:
But if I click one of the Objects, getView() is called, and the selected Layout and TextViews are rendered properly (apparently I selected "GMU - Pentagon"):
What am I missing to get the Spinner's popup list to display ALL my bus route items rendered correctly?
I think you need to override getDropDownView to deal with spinners
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
BusRoute route = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.bus_route, parent, false);
}
TextView tvBusRoute = (TextView) convertView.findViewById(R.id.tvBusRoute);
TextView tvBusRouteNumber = (TextView) convertView.findViewById(R.id.tvBusRouteNumber);
tvBusRoute.setText(route.routeName);
tvBusRoute.setTag(route.route);
tvBusRouteNumber.setText(route.route);
if (!route.routeColor.equals("")) {
tvBusRouteNumber.setBackgroundColor(Color.parseColor(route.routeColor));
}
return convertView;
}

Changing background color of ListView item upon clicking a Button

Apologies if this question has been asked previously.
I have a ListFragment that contains a Button in each list item. Clicking on the Button should change the background color of that particular list item. I understand that the ListView inside the ListFragment refreshes itself implying that if a user scrolls it is likely that a list item that was not previously clicked will have its background color changed.
Many of the solutions I have come across involve storing the position of the list item that was clicked in an overridden getView(int position, View convertView, ViewGroup parent) method implemented in a custom adapter (that extends SimpleAdapter in my case).
However my problem is compounded by the presence of a Button inside every list item implying that the Button will not be clickable unless I attach an OnClickListener inside a custom adapter (this part is done). Now, trying to store the position of the Button's list item fails because the saved position is always a refreshed position and not the absolute position of the list item. I also tried setting tags for each button but even those get recycled as the page scrolls, which is (unfortunately) expected behaviour considering the design of ListView.
I understand that this problem is easily solvable if the a list item does not have children that need to be clicked. But what if there are children within every list item that need to respond to clicks separate from the parent view that contains each list item ? I have also tried using selectors to manipulate a list item's background but that hasn't helped either.
Here is my Custom Adapter's getView method:
#Override
public View getView(int position, View convertView, ViewGroup parent){
View view = convertView;
final int pos = position;
if(view == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.fragment_layout, null);
Button button = (Button) view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
Log.d("CLICKED POSITION",Integer.valueOf(pos).toString());
View parent = (View) v.getParent();
parent.setBackgroundColor(Color.GREEN);
}
});
}
return view;
}
And the XML layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1"
android:descendantFocusability="blocksDescendants"
android:layout_margin="5dp"
>
<ListView android:id="#id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/label"
android:layout_gravity="start"
/>
<TextView
android:id="#+id/text_id"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="end"
/>
<Button
android:id="#+id/button"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="#string/button"
android:layout_margin="2dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:clickable="true"
/>
</LinearLayout>
I have spent many hours on this problem and I am unable to arrive at a solution. Any direction, guidance or a solution would be most appreciated.
In your Custom Adapter's getView() method, you are inflating the view and attaching the onclicklistener only if the convertView is null. convertView IS the recycled view. If convertView is not null, then you need to change the values in that view. Your getView() method should be like this instead
#Override
public View getView(int position, View convertView, ViewGroup parent){
View view = convertView;
final int pos = position;
//No recycled view, so create a new one
if(view == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.fragment_layout, null);
}
//By this line, we either have a view that is created in the if block above or passed via convertView
Button button = (Button) view.findViewById(R.id.button);
//attach listener to the view, recycled or not
button.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
Log.d("CLICKED POSITION",Integer.valueOf(pos).toString());
//parent not required as we are have the view directly
//View parent = (View) v.getParent();
v.setBackgroundColor(Color.GREEN);
}
});
return view;
}
Indeed you should also be changing any values associated with that item according to that position, if they change. For example, if each button displays the position in the list, you should also add the following line
button.setText("Button " + position);

Invisible TextView's start to be visible when scrolling ListView

I've got huge problem that I don't understand. I have got custom ListView with my own adapter. Each row in ListView has two TextViews - one is a title and the second one is invisible at start. It's going to be visible when there is something new in this item.
In my adapter I set title for every row and set second TextView to be visible when it should be. When I run my app it's fine, but when i scroll down and up the list almost every row is changing invisible TextView to be visible!
I don't know why, but I spaculate that this is something with convertView. Can anybody tell me what's going on?
My adapter:
public class MyListAdapter extends BaseAdapter {
#SuppressWarnings("unused")
private Activity activity;
private ArrayList<String> titles;
private LayoutInflater inflater;
public MyListAdapter (Activity activity, ArrayList<String> titles) {
this.activity = activity;
this.titles = titles;
inflater = (LayoutInflater)activity.getLayoutInflater();
}
public int getCount() {
return titles.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if (convertView == null) {
vi = inflater.inflate(R.layout.wpis_list_row, null);
}
TextView title = (TextView)vi.findViewById(R.id.movie_title);
title.setText(titles.get(position));
String name = titles.get(position);
if (name.equals("Name 1") || name.equals("Name 2")
|| name.equals("Name 3")) {
TextView news = (TextView)vi.findViewById(R.id.new_sounds);
news.setVisible(0);
}
return vi;
}
}
and my layout for single row:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/LinearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/list_selector"
android:orientation="horizontal"
android:padding="5dip" >
<TextView
android:id="#+id/movie_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="9"
android:layout_marginLeft="#dimen/list_margin"
android:text="#string/entry"
android:textColor="#FFFFFF"
android:textSize="22sp" />
<TextView
android:id="#+id/new_sounds"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:textColor="#8C1717"
android:textSize="13sp"
android:text="#string/news"
android:visibility="invisible" />
</LinearLayout>
Sometimes you are setting the visibility of the text view as visible, based on some if condition . Make sure to change the visibility to gone in the else part.I hope this work . Also you are assigning view view= convertview and then doing if( convertview = null) . Assign the view to convert view in the else part of this check.
To make a View invisible in its layout, use android:visibility attribute set to gone or invisible depending on what you want to do.
Programmatically, to change visibility, call the View.setVisibility(VISIBILITY_YOU_WANT) method. There are some constants in View class you can use: View.GONE , View.VISIBLE , View.INVISIBLE.
BTW, read this post to better understand the ListView recycling.

Adding image to listview after listview item click

I am developing an app which has a listView having 1 textView which displays the content and one imageView. What i want is, when i click the listView i want to set the imageView with the tick mark image which i have. Its working fine. Once i click the listView, the tick mark image is loaded on that listview item on which i clicked.
The problem arises when i scroll. When i scroll, i could see some other listview item down below has a tick mark loaded. not sure how the image was set on that position.
I have read somewhere that when the listView is scrolled, the view is refreshed. Is that causing the problem?
Can anyone help how can iresolve this? I want the image to be shown(loaded) on the listView item on which i clicked and now other listView item.
Below is the xml stating listView items
method_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#android:color/white"
android:text="This is a check box button which reacts upon the check that user clicks. I am testing it with the big string and checking how it looks" />
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView1"
android:layout_centerHorizontal="true" />
<ImageView
android:id="#+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/imageView1"
android:layout_alignParentRight="true"
android:layout_marginRight="34dp" />
</RelativeLayout>
Below is the part of class snippet:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.method_list_main);
final ListView list = (ListView)findViewById(R.id.listView1);
adapter=new MethodLazyAdapter(this,ARRAY.preparationSteps,ARRAY.timeToPrepare,ARRAY.arrowValue,noOfSteps,list);
list.setAdapter(adapter);
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// TODO Auto-generated method stub
RelativeLayout ll = (RelativeLayout) view;
ImageView image = (ImageView)ll.findViewById(R.id.imageView2);
if(tick[position]){
tick[position] = false;
image.setImageResource(0);
}
else{
tick[position] = true;
image.setImageResource(R.drawable.select_right);
}
System.out.println("Position is: "+position);
}
});
}
Initially all tick[i] value is set to false.
Below is the getView function of adapter class
public View getView(final int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.method_item, null);
TextView text = (TextView)vi.findViewById(R.id.textView1);
text.setText(preparationSteps\[position\]);
return vi;
}
Try this to get what you want
in public area add this variable
public SparseBooleanArray checked = new SparseBooleanArray();
then in onItemClick
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
boolean stat = checked.get(position, false);
checked.put(position, !stat);
adapter.setChecked();
System.out.println("Position is: "+position);
}
});
and in Adapter Class
If adapter not sub class in activiy add variable in public area
private SparseBooleanArray checked = new SparseBooleanArray();
and add this method to class
public void setChecked(SparseBooleanArray ch){
checked = ch;
notifyDataSetChanged();
}
Or if it sub class use our cheked variable we defined it up
then in getView method
public View getView(final int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.method_item, null);
TextView text = (TextView)vi.findViewById(R.id.textView1);
text.setText(preparationSteps\[position\]);
ImageView image = (ImageView)vi.findViewById(R.id.imageView2);
if(checked.get(position, false)){
image.setImageResource(0);
}
else{
image.setImageResource(R.drawable.select_right);
}
return vi;
}
Please let me know if this help you.
Check out this post:
android - populating ListView with data from JSONArray
the reason for that is bacouse your are using your converted view wrong.
follow the example code on the post i paste.
if you will inflate your row view every time this problem will disappear. but this implementation is not recommended.

Change text color for ListView items

How do I change the text color for the items that are added to a ListView. I need to change the colors programmatically in code based on certain conditions and changing different rows to different text colors(e.g. row 0 = red, row1= white, row3= blue etc). Setting a text color in the xml layout will not meet my requirements. Here is my code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listview);
setListAdapter(new ArrayAdapter<String>(ListViewEx.this,
R.layout.list_item_1, Global.availableDecks));
//something like this
//listview.getPosition(0).setTextColor(red);
//listview.getPosition(1).setTextColor(white);
//listview.getPosition(2).setTextColor(blue);
and my xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/label"
android:layout_width="match_parent"
android:layout_height="35dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="30px"
android:layout_marginLeft="5px"
android:singleLine="true"
/>
Implement your own ArrayAdapter and override the getView() method:
public class Adapter1 extends ArrayAdapter<String> {
public Adapter1(Context context, int resID, ArrayList<String> items) {
super(context, resID, items);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
if (position == 1) {
((TextView) v).setTextColor(Color.GREEN);
}
return v;
}
}
Don't forget to provide an alternative else clause to set the color to the default so you don't have problems when you're dealing with a recycled row.
Then in your activity:
setListAdapter(new Adapter1(ListViewEx.this,
R.layout.list_item_1, Global.availableDecks));
use android:textColor="hex code" parameter inside the TextView tag
You can change through xml and java code(runtime) also....
in xml widget you need to define ::
android:textColor="Hex code"
Like ::
android:textColor="#000000"
at runtime you need to define ::
TextView tv = (TextView) aView.findViewById(R.id.txvx);
tv.setTextColor(Color.RED);

Categories

Resources