Set margin to "standalone" view - android

This might be just bad practice, but android gui keeps frustrating me as always. I have this standalone view called primary_button under res/layout:
<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:background="#drawable/primary_button"
android:textColor="#color/light_warm_gray"/>
and its custom background "primary_button" shape under res/drawable:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#color/light_olive" />
<corners android:radius="10dp"/>
<size android:height="40dp" android:width="40dp" />
</shape>
Now the problem is, when I set layout_margin to say 10dp, nothing is set because at that point when I inflate using that line:
Button b = (Button)View.inflate(this, R.layout.primary_button, null);
it has no layout parent (obviously needs to set layout params). I want neat code, and setting *Layout.LayoutParams in code all the time is a pain.
Shape padding, and button padding, didn't do what I wanted, but what they are intended to do. (In that case they just enlarged the button shape)
Another way i thought of, was to set a zero-alpha stroke around it, but that is a horrible solution.
I wonder how the stock buttons handle this. I mean they just leave a nice margin between them (around 15dp?) without having to set layout params. Shouldn't this somehow happen with a custom view as well?

Try the following:
View.inflate(this, R.layout.primary_button, parentView);
I suppose there is an add view method called later. try both by keeping it and removing it.

Related

How to draw a rectangle around multiple views

I’d like to achieve the following look in my app to try and group the views into a more logical layout.
I was thinking of creating a Shape Drawable for the rectangle something along the lines of this:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="#android:color/white"/>
<corners android:radius="12px"/>
<stroke android:width="2dip" android:color="#000000"/>
</shape>
But what I’m not sure about how to place the rectangle in the view. Most of the examples I’ve seen are placing a drawable as a background for a single view, not multiple views as per the above.
Do I need to create some sort of ‘blank’ view which holds no purpose but to house the rectangle? How would I go about this?
Everything is currently defined in a constraint layout.
Create a layout around the views and set its background as the drawable you created.
You will have to add this as a background to the Viewgroup where all these views are.
For eg. add this drawable as background to the relative layout.
Thanks for the comments all. Thought I'd update this with what I implemented as although the other answers were correct, I still didn't quite grasp what was required, so here's some additional information:
Create a file called 'rectangle.xml' in the drawable folder, with the following content:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="#android:color/white"/>
<corners android:radius="12px"/>
</shape>
Then in the layout file in which I wanted to place the rectangle, I added the following view. The key bit that I didn't understand was how to specify the size/position of the rectangle. This was achieved by defining the following constraints to wrap it around the items I wanted.
<View
android:id="#+id/myRectangleView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="#id/unit_spinner"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="#id/time_label"
android:background="#drawable/rectangle"
android:elevation="2dp"
/>
Couple of other points I struggled with:
Even though I defined this view before all the views it surrounds,
the arrows on the spinners were displaying behind the rectangle. To fix this, I had to use the elevation property on the view, and set all the other views to be higher.
I struggled to get the position of
the rectangle where I wanted it using the margin/padding of the
rectangle view, so instead had to add padding to the views it was
surrounding. Not sure if this is the right approach - I'm still
toying with it.

Android add border to button without losing material theme (using drawable)

I have a simple button
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/add"
android:backgroundTint="#color/add_bg"
android:textColor="#color/add_fg"
<!--android:borderColor?="#color/button_border"-->
android:text="#string/add"/>
I would like to have white background, blue text and blue border around. I am aware that I can achieve that through a drawable as shown here and in numerous other places. However I have observed that if you add a drawable to the button then it will lose all of its material properties (such as shadow and also upon clicking having the fancy ripple animation). So how would I add a border around the button without losing the material theme animations (shadow and tipple animation on click)?
Most of the items that android comes with are simply a pre-packaged set of attributes.
It would be almost impossible to expect the Android API developers to include a pre-packaged set of attributes for every possible color/border combination, but there is always a solution!
Unfortunately,as you mentioned, the solution does reside in creating your own custom XML file which can often be intimidating until you get the hang of it. Once you do, you too will marvel at the flexibility it allows.
Specifically for your situation, there are two options...
1) Create a custom XML border drawable.
2)under your buttons background property set your new custom border drawable
3)then also set the ripple effect under your buttons xml properties by adding:
android:foreground="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
----OR----
A more complex way is to make a drawable like the one below. This will add the "ripple" button effect as well as a custom shadow, button color, and border color!
"For anybody reading this later that may be less experienced)
1)In your project view go to res/drawable
2)right click the folder itself and select new/drawable resource file
3)Enter a file name my_ripple_button.xml(the root doesn't really matter because you wil replace it with the below code)
4)Click on the text tab if you aren't already there
5)select all text and basically replace with the following: (creating a custom color border is basically the same steps)
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/colorPrimaryDark">
<item android:id="#android:id/ripple">
<shape android:shape="rectangle">
<solid android:color="#color/colorPrimaryDark" />
<corners android:radius="#dimen/button_radius_large" />
</shape>
</item>
<item android:id="#android:id/background">
<shape android:shape="rectangle">
<gradient
android:angle="90"
android:endColor="#color/colorPrimaryLight"
android:startColor="#color/colorPrimary"
android:type="linear" />
<corners android:radius="#dimen/button_radius_large" />
</shape>
</item>
</ripple>

Android recyclerview divider aligned to internal layout views

I know this gotta have a simple answer, so here goes:
This is an image of a famous "chat" Android app. My question is how can I simulate the behaviour in red, namely a divider that does not take the parent's screen width, but starts aligned with the text views in the recyclerview item inflated layout?
I have created a chatlist_divider.xml drawable as below:
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="80dp"
android:insetRight="16dp">
<shape>
<size android:height="1dp"/>
<padding
android:bottom="2dp"
android:left="8dp"
android:right="8dp"
android:top="2dp"/>
<solid android:color="#color/colorDivider"/>
<corners android:radius="48dp" />
</shape>
</inset>
and programatically have used it as follows:
mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), R.drawable.chatlist_divider));
but ofc the result will not be as perfect as in the image above, because Im playing with the insetLeft property of the inset, until it feels right:
Is this the best that can be done? I wanted a proper and definite alignment to the TextViews inside the inflated layout of each list item, not just trial and error.
(I could also create a <View> below the textviews (which are in a Layout of its own) to simulate the divider, but then how can I assign it the .xml drawable?)
Any thoughts?
No need to use mRecyclerView.addItemDecoration.
Simply create the divider as a regular View with your drawable xml as background and add it to your item's layout xml.
If you make the root of the layout RelativeLayout, you can have the divider toRightOf="#+id/some_other_view", so it's aligned properly with the item's views.
<View
android:id="#+id/divider"
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_toRightOf="#+id/my_photo_view"
android:background="#drawable/chatlist_divider" />

Why Android layer-list drawable so intelligent?

I can't dig deep into how android implements its layer-list drawable. But I find it interesting and I can hardly know why this happens.
Here are some drawables:
the nine-patch xml
<?xml version="1.0" encoding="utf-8"?>
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/cam2tst_ripple_bg_img">
</nine-patch>
the shape xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<padding
android:left="#dimen/cam2tst_ripple_horizontal_padding"
android:top="#dimen/cam2tst_ripple_vertical_padding"
android:right="#dimen/cam2tst_ripple_horizontal_padding"
android:bottom="#dimen/cam2tst_ripple_vertical_padding" />
<solid android:color="#android:color/holo_green_dark" />
</shape>
the ripple xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#android:color/holo_green_light">
<item android:drawable="#drawable/cam2tst_ripple_shape"></item>
</ripple>
the layer-list containing all above
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/cam2tst_ripple_bg_img" />
<item android:drawable="#drawable/cam2tst_ripple_base" />
</layer-list>
Unfortainately I still can't get my screenshot thing work on my L preview, but I can describe it.
What I get is the shape (which i obviously didn't set its size explicitly) doesn't cover over the whole nine-patch! The un-streched part of the nine-patch is magically considered as some kind of "auto padding thing". What I was expecting (ok I was expecting exactly what android has done for me, I mean what I was... supposing...) is something not so positive: the not-particularly-sized shape drawable covering the entire nine-patch just as if the latter is a normal png.
But the shape does magically avoid the un-stretched part of the nine-patch and overlays only above the streched-part of the nine-patch.
This is awesome...but confusing, why? I may not able to dig that deep into the source but this do sounds anti-intuition (but nice). I want to know the reason though. So I post this here.
Since I tagged this as android-L because I am working on one. But I think this shall be working from something like gingerbread.(just to replace the ripple drawable with something else, maybe a inset drawable etc.)
This effect is caused by the combination of two things:
All nine-patch drawables have a padding area defined automatically from the edges of the content area. The content area can be defined either explicitly, using the right and bottom lines at the border, or implicitly from the stretchable area defined by the left and top lines.
Layer-list applies the padding on each layer cumulatively to the next layer by default*, effectively treating each layer as the content of the previous layer.
* Lollipop has introduced a new attribute for disabling this behavior.

Why does assigning a color to the background of my ListView element not cover the entire ListView background, while assigning a drawable does?

I have a ListView that sits on the left side of a tablet-size screen. My goal was to give it a solid background with a border on the right, then apply an overlapping background on the list element to break that border so that it appears to be a part of the view on the right.
The ListView Background
I achieved the right border using a <layer-list> drawable as suggested by Emile in another question:
rightborder.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#color/black" />
</shape>
</item>
<item android:right="2dp">
<shape android:shape="rectangle">
<solid android:color="#color/white" />
</shape>
</item>
</layer-list>
...and here's the ListView definition for good measure:
<ListView
android:id="#+id/msglist"
android:layout_width="300dp"
android:layout_height="match_parent"
android:divider="#color/black"
android:dividerHeight="1dp"
android:background="#drawable/rightborder"
android:paddingRight="0dip">
</ListView>
<!-- I added the android:paddingRight after reading something
about shape drawables and padding, don't think it actually
did anything. -->
Attempting to override it with a color
In order to achieve the desired effect, I placed the following in the getView function of my adapter:
//If it's selected, highlight the background
if(position == mSelectedIndex)
convertView.setBackgroundColor(R.color.light_gray);
else
convertView.setBackgroundResource(0);
However, using this method, the black border of the ListView's drawable remained visible, and only the white part of the background was replaced by gray. Here's a screen capture:
Fixing it with a drawable
On a hunch, I replaced the color I was assigning with a shape drawable:
selectedmessage.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle"
xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="#color/light_gray" />
</shape>
getView snippet:
//If it's selected, highlight the background
if(position == mSelectedIndex)
convertView.setBackgroundResource(R.drawable.selectedmessage);
else
convertView.setBackgroundResource(0);
This achieves the desired result, as shown below:
The question:
Why does assigning a rectangle as the background for my ListView element cover the entire view, while assigning the color allows the black border to show through? I'm happy it's working, but I'd like to know why Android is rendering the view this way so I can learn more about how Android renders Views.
Other notes:
I'm running the project in the stock Android 3.2 emulator, if that makes any
difference.
One clue may be that the light_gray color background seems to render darker than the light_gray shape resource.
I doubt it makes a difference, but light_gray is:
<color name="light_gray">#FFCCCCCC</color>
You can't do this:
convertView.setBackgroundColor(R.color.light_gray);
setBackgroundColor does not take a resource id : http://developer.android.com/reference/android/view/View.html#setBackgroundColor(int)
So your getting some incidental behaviour that isn't doing what your expecting.
You would have to do:
convertView.setBackgroundColor(getResources().getColor(R.color.light_gray);
http://developer.android.com/reference/android/content/res/Resources.html#getColor(int)

Categories

Resources