Android spinner popup dropdown position and size - android

I managed to change the Spinner background and it's popup dropdown background. I can adjust the popup android:dropDownHorizontalOffset and android:dropDownVerticalOffset.
I also have a custom layout for the spinner items.
But, i am stuck with this look:
Notice how the items are outside the boundries of the popup dropdown. How can I fix that? Is there a way to insert padding for the top and bottom of the items somehow?
<Spinner
android:id="#+id/branchesSpinner"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:background="#drawable/dropdown_base"
android:dropDownHorizontalOffset="-5dp"
android:dropDownVerticalOffset="50dp"
android:paddingBottom="10dp"
android:paddingLeft="20dp"
android:popupBackground="#drawable/rounded_rectangle_4"
/>
spinner_item_custom_layout:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:textColor="#color/charcoal"
android:textStyle="bold"
tools:text="Select Branch"></TextView>
N.B: The backgrounds I added are .PNG images and not XML

Because you are using a png file as popup background for the spinner so there are 2 limitations
If you run the app on devices which have high screen density, your spinner background might be stretch and look so ugly.
You cannot set padding for you popup background, that why sometimes your content is not looking good as you expected.
Solution: Using 9-patch images. You can take a look a guide from Android official site about how to use draw9patch
I've just used draw9patch tool to edit your rounded_rectangle_4.png.
You can replace with your current background then give it a try.

You need to create custom adapter for your spinner.
Then, in getDropDownView method of the adapter class you need to set top margin of the dropdown item when the position is 0 using below code
public static void setMargins (View v, int l, int t, int r, int b) {
if (v.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
p.setMargins(l, t, r, b);
v.requestLayout();
}
}
Just make your logic to compare the position of dropdown child.
Note that you need to set only top margin.

Related

How to get background color for Android ListView item to extend all the way to the end?

I am trying to force the background color for certain ListView items in my app to be different than all the others. The examples here on Stack Overflow and elsewhere are pretty straightforward. But for some reason the background color changes only as far as the width of the top TextView. Notice in the attached pic there are two TextView items on each row.
I decided to log the width of the list view item and oddly it turns out it has a width of 0. Unexpected, of course, but maybe at the time of the logging (execution of getView) it has not yet been expanded to their full with.
I am setting the background color in the getView() call, so its code is below. The xml for the item is below that.
#Override
public View getView(int arg0, View arg1, ViewGroup arg2)
{
if(arg1 == null)
{
LayoutInflater inflater = (LayoutInflater) m_context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
arg1 = inflater.inflate(R.layout.listitem_assessments, arg2, false);
}
TextView title = (TextView)arg1.findViewById(R.id.tvTitle);
TextView date = (TextView)arg1.findViewById(R.id.tvDate);
if (arg0 <= m_list.size())
{
Attrs attrs = m_list.get(arg0);
title.setText(attrs.m_sTitle);
date.setText(attrs.m_sDetail);
if (Character.isDigit(attrs.m_sActivationCount.charAt(0)))
{
if (!attrs.m_sActivationCount.equals("0"))
{
Log.i("Adapter", " Width of list item view is: " + arg1.getWidth());
arg1.setBackgroundColor(Color.YELLOW);
}
else
Log.i("Adapter", "Width of list item view is: " + arg1.getWidth());
}
else
arg1.setTag("");
return arg1;
}
Here is the xml resource for the ListView items:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="10dp"
>
<TextView
android:id="#+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_marginLeft="23dp"
android:layout_marginTop="10dp"
android:text="Assessment title"
android:textStyle="bold"
android:textSize="16sp" />
<TextView
android:id="#+id/tvDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/tvTitle"
android:layout_alignLeft="#+id/tvTitle"
android:background="#color/LightBlue"
android:text="date or author" />
</RelativeLayout>
Notice I'm using match_parent for the list item width so seems it would stretch out fully, and certainly not be 0. Nor since it is not wrap_content should it extends only as far as the widest TextView.
To be clear, I need the background color, Yellow, in my test, to extend all the way to the right. Any help greatly appreciated.
UPDATE
I have been able to log some accurate width info by moving the code into the OnItemClickListener event. The width of the entire ListView is 1312, but the width of the ListView items are indeed too short, and vary as the yellow backgrounds reveal. The first item is 696. It is clear now that the layout is not stretching things out to match the parent. How to force it to do that? It seems to be behaving as if I am using match_content instead of match_parent for the layout_width. Trying now to verify at run-time (at inflate time) the layout_width.
The problem is in the width of your TextViews as they are set to wrap_content.
Change them to
android:match_parent

Make a view in recyclerview cell float above a previous cell

I am using a RecyclerView to show a list of videos.
Each item in the list holds Video and SeekBar (and more stuff actually but not relevant here) in a RelativeLayout, as follows:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/performance"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.my.company.VideoView
android:id="#+id/the_video"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:keepScreenOn="true"
android:scaleType="fitCenter" />
<SeekBar
android:id="#+id/the_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:alpha="1.0"
android:maxHeight="#dimen/seekbar_height"
android:minHeight="#dimen/seekbar_height"
android:padding="0dp"
android:progressDrawable="#drawable/my_progressbar"
android:thumb="#drawable/my_progressbar_circle"
android:translationY="-5dp" />
</RelativeLayout>
As you can see I added a android:translationY property that brings the SeekBar up a little so it would be partially positioned on top of the previous cell, i.e. the previous Video.
However it remains partially hidden. I can only see the part that is in the RelativeLayout in which is it declared.
I tried calling bringToFront() on the seekbar and on the RelativeLayout (performance) itself - but that did not help.
Probably the question is not relevant to RecyclerView only. Being somewhat new in android dev I am not sure if I can place a view that is declared inside a RelativeLayout to show up outside of its borders.
Hope I was clear, need your help. Tx.
By default, every view is clipped to its parent size.
You could try to disable this clipping, by adding this in your RelativeLayout XML attributes:
android:clipChildren="false"
android:clipToPadding="false"
or in code
viewGroup.setClipChildren(false);
viewGroup.setClipToPadding(false);
In your case, it seems that either RecyclerView or LinearLayoutManager consider that previous items should be displayed over following ones. One way could be to use RecycleView decoration to overlap :
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
private final static int vertOverlap = -10;// TODO : do not forget to convert dp in pixels
#Override
public void getItemOffsets (Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.set(0, vertOverlap, 0, 0);
}
});
So, you would not need to use translationY on your SeekBar, but rather to add some paddingTop to your VideoView :
android:paddingTop="5dp"
That way, I think you could hide the SeekBar if needed, and cell overlapping would not be visible.
Follow this answer with same case only the difference is it is overlapping next item of Recycleview https://stackoverflow.com/a/40603773/3839498

How to add two drawableRight in EditText?

I am able to add one drawableRight in EditText in android easly and on click event working perfectly in case of one drawableRight. But I need two drawableRight in EditText.
So, How can I add two drawableRight in EditText? and I also need to perform click event on both drawableRight separately.For example I want to add yellow star in EditText like as given below image and on click on rightmost image I want to open contact book of phone and on click of yellow star I want to call user's favourite numbers list.
So How can I do this? Any Idea?
There is no native support for this, so you got two options here:
Easy solution: Create a Linear layout with tow image views on the right side, those will be your drawables.
The hard way: Extend a Drawable class and implement your own onDraw method where you will draw the two drawables. Than use that one for your text view.
You can't. The TextView can contain only one drawable on either of its sides. The only options you have are:
Create custom View.
Take some of the ViewGroup descendants (RelativeLayout/FrameLayout/etc) and put the TextView along with the two ImageViews in it.
Just place two Drawables into EditText using RelativeLayout.
To set inner padding, place an invisible drawableRight into EditText:
/res/values/dimens.xml
<resources>
<dimen name="iconSize">32dp</dimen>
</resources>
/res/layout/my_layout.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/editText"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:inputType="textAutoComplete"/>
<ImageButton
android:id="#+id/imageButton1"
android:layout_width="#dimen/iconSize"
android:layout_height="#dimen/iconSize"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="#drawable/ic_action_1"/>
<ImageButton
android:id="#+id/imageButton2"
android:layout_width="#dimen/iconSize"
android:layout_height="#dimen/iconSize"
android:layout_toLeftOf="#+id/imageButton1"
android:layout_centerVertical="true"
android:src="#drawable/ic_action_2"/>
</RelativeLayout>
In your Activity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
EditText editText = (EditText) findViewById(R.id.editText);
int iconSize = (int) getResources().getDimension(R.dimen.iconSize)
Drawable drawable = ContextCompat.getDrawable(context, R.drawable.ic_action_1);
drawable.setBounds(0, 0, iconSize * 2, 0); // that is the trick!
editText.setCompoundDrawables(null, null, drawable, null);
}

Adding bottom margin to ListView last element

I need to add to add ListView with complicated items background: different for even/odd and rounded corners at the top and bottom. It looks like this:
I have implemented all this stuff via level-list, but there is one more thing I want to do.
Now the bottom item is near the bottom of the screen. It is better to add some space.
I don't want to add bottom margin to ListView, I need margin only for last item.
The ways I see to do this:
Footer
A kind of hack – add footer with empty TextView to ListView. But footers are quite unstable things, they usually disappear after notifyDataSetChanged and there is no way to get them back
Image with transparent pixels
I asked designer to add transparent pixels to bottom background resource. Unfortunately, in this case vertical centering is completely broken.
For example, there is 9patch like this:
And layout like this:
<?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"
>
<!-- View with background with transparent pixels on bottom -->
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
android:id="#+id/item"
android:background="#drawable/some_bgr"
android:padding="10dp"
>
<TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"
android:text="Title"
android:layout_gravity="center"
android:textSize="18sp"
/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="Detail"
android:layout_gravity="center"
android:textSize="18sp"
/>
</LinearLayout>
<!-- Just for marking place took by view -->
<FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"
android:layout_below="#id/item"
android:background="#88ff55"
/>
</RelativeLayout>
The result:
As you see, centering is not working. Unfortunately.
(BTW, if specify this 9patch as background for TextView, centering works good. If you know any article, explaining this, please let me know.)
Add bottom margin to last item in Adapter implementation
That should work, but for unknown reason I still can't get it work.
I don't like this way, because I don't like to modify dimensions in code.
So
There is already imaginary way – construct some XML drawable with particular bitmap and margin. According to drawables concept it should be possible, but I can't find implementation. May be somebody knows?
Any other ideas?
In your ListView, set a paddingBottom and clipToPadding="false".
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="8dp"
android:clipToPadding="false"
android:scrollbarStyle="outsideOverlay"/>
This also works for RecyclerView.
Only use android:scrollbarStyle="outsideOverlay" if you want the scroll bar to not overflow into the padded area.
add an empty footer in your list like this:
TextView empty = new TextView(this);
empty.setHeight(150);
listview.addFooterView(empty);
you can also do it from code if you want, for example here I react to
to EditText different situations:
if(s.toString().length()>0)
{
contacts_lv.setClipToPadding(false);
contacts_lv.setPadding(0,0,0,270*screenDensity);
}
else
{
contacts_lv.setClipToPadding(true);
contacts_lv.setPadding(0,0,0,0);
}
Clocksmith's answer is the best and pretty clever. You can also create an empty footer view.
Add these two lines in your listView XML code:
android:transcriptMode="alwaysScroll"
android:stackFromBottom="true"
Another solution might be that you make a mock view with certain height.
In your adapter in getViewCount return 2.
In getCount return yourData.size+1.
In getViewType check if the element is last element return 2;
Use this type in getView to populate the mockview.
I guess you want to add margin only to last item:
So you can do in this manner, in your getview method the index of the list item and check if its the last item, then progrmatically add margin to the view.

Android horizontal LinearLayout with wrapped text in TextView

I've observed a behavior with layout_weight that I can't explain. The following is a trivial example:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
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:layout_gravity="center_vertical"
android:text="This is a very very very very very very very very very very very very very very very long string."
android:layout_weight="1"
/>
<View
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center_vertical"
android:background="#ffffffff"
/>
</LinearLayout>
In a QVGA display, the TextView wraps the text. The white square is displayed to the right of the text.
However, if I remove android:layout_weight="1" from the TextView, the TextView now takes up the entire display width. The white square is no longer displayed.
Why would layout_weight in the TextView affect whether or not the white square is displayed? Shouldn't the View with the white background always be assigned 32dpx32dp first? (It makes no difference if the view were any other types - ImageView or TextView).
The problem I was working on is that I want the white square to always be displayed to the right of the TextView (whether or not the text is wrapped), but I don't want any empty space between the TextView and the white square. (If I add android:layout_weight="1" to the TextView, then there is a gap if the text is not wrapped.)
Any help would be appreciated!
To answer my question #1: One thing I learned by looking at the source for LinearLayout: Not only does layout_weight assign unused space to a child, it also shrinks a child with layout_weight if the child extends beyond the bounds of the LinearLayout. That explains why a TextView with wrapped text is shrunk in my layout.
As for the answer to my question #2, I think you meant android:toRigthOf instead of android:layout_alignRight. Using a RelativeLayout instead of a LinearLayout doesn't change the layout behavior. The tricky part is placing a view immediately to the right of a TextView, without gaps, whether or not the text is wrapped. Setting a maxWidth would limit the TextView's width, but that solution doesn't scale across portrait/landscape and different display dimensions.
Solution - Looks like Dyarish's solution is the best available. My layout problem exists regardless of the layout you use. The key is to set a maxWidth for the TextView so that it doesn't take up the all of the horizontal space in the layout. Because hardcoding a android:maxWidth value in the TextView doesn't scale across different displays, setting the maxWidth at runtime, as Dyarish suggested, is a good solution.
Hopefully this is what you are looking for.
First off, here is a great resource I found for Creating UI's.
layout_weight - Specifies how much of the extra space in the layout to be allocated to the View.
If you want to ensure that the white square is always to the right of the textview, you can use a Relative View, and add the parameter to the view. android:layout_alignRight="+id#yourTextViewID". This should always make the box appear right beside the textView area. You should probably also add something like android:maxWidth="250px" This will ensure that you don't push the white box completely out of the screen.
Here is a code sample:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:maxWidth="250px"
android:id="#+id/TextForWhiteBox"
android:layout_height="wrap_content"
android:layout_gravity="center|left"
android:text="This is a very very very very very very very very very very very very very very very long string."
/>
<View android:background="#ffffffff" android:layout_width="32dp" android:layout_height="32dp" android:id="#+id/view1" android:layout_toRightOf="#+id/TextForWhiteBox"></View>
</RelativeLayout>
You could also add to the View:
android:layout_alignTop="#+id/TextForWhiteBox" android:layout_alignBottom="#+id/TextForWhiteBox"
to make the white box the same size as the TextView.
Firstly I've tested the code from my other answer and it does exactly what you've described you've wanted. (unless I'm misunderstanding what you are asking for). You definitely do not want to use the android:layout_alignRight which is not what is in the code sample. That would simply keep the box on the right hand of the screen and not be affected by the textview at all. This sample uses android:layout_toRightOf="#+id/TextForWhiteBox" which is possible due to it being a relative layout. Since the Relative Layout allows you to place objects in relation to others. That line will always place the box just to the right of the textview with no gaps.
As for the screen orientation changes:
When the orientation changes it creates a new instance of the view.
Here is a simple solution.
//Add to oncreate in your Activity
private TextView textStatus;
textStatus = (TextView) findViewById(R.id.TextForWhiteBox);
// This get's the width of your display.
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int width = displaymetrics.widthPixels;
// Now you know the screen orientation, and it's width. So just set the maxwidth of the text view to match the display width - the pixels of your white box.
textStatus.setMaxWidth(width - 32); // 32 is here because you already know the size of the white box. More logic is needed to dynamically get this value, because you would need to wait for the activity to be fully created.
}
Here is the main.xml I used:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:id="#+id/TextForWhiteBox"
android:layout_height="wrap_content"
android:layout_gravity="center|left"
android:text="This is a very very very very very very very very very very very very very very very very very very very long string."
/>
<View android:background="#ffffffff" android:layout_width="32px" android:layout_height="32px" android:id="#+id/view1" android:layout_toRightOf="#+id/TextForWhiteBox"></View>
</RelativeLayout>
You might need some additional logic to keep screen values.
This code has been tested, you should be able to literally copy and paste this to work as you asked.
Also depending on your logic you could use something like this to return the screen orientation.
int orient = getResources().getConfiguration().orientation;
Hope this helps!
If this helped you, please click the accepted button. =) Cheers!

Categories

Resources