Prevent RelativeLayout from wrapping around the background image - android

I have a RelativeLayout. I wanted to apply a shadow effect on it, so I defined a custom background (updatebg.xml):
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/background" >
<shape android:shape="rectangle">
<solid android:color="#449966"/>
</shape>
</item>
<item android:id="#+id/shadow">
<bitmap android:src="#drawable/shadow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</item>
</layer-list>
And the RelativeLayout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/layoutP"
android:background="#drawable/updatebg"
>
</RelativeLayout>
Everything works great, except that the RelativeLayout gets stretched to the same height as the background image height (shadow). If I have content inside the RelativeLayout that takes less height than the height of the shadow background image, then the RelativeLayout will be stretched to "wrap around the background" as well, instead of wrapping around just the content inside RelativeLayout.
I need for the background image to ether adjust to the parents height (RelativeLayout) or get cropped off. Any hints on how to accomplish this? Thanks!
I'm trying to apply the gradient type of shadow from top to bottom:

Edit
Maybe I have misunderstood what you said "shadow effect", if you just want a gradient, use <gradient> drawable.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="#+id/background" >
<shape android:shape="rectangle">
<solid android:color="#449966"/>
</shape>
</item>
<item>
<shape
android:dither="true"
android:shape="rectangle" >
<gradient
android:angle="270"
android:endColor="#7fffffff"
android:startColor="#7f000000" />
</shape>
</item>
</layer-list>
The result is like:
Original Answer
You should consider using a 9-Patch png instead. It's like this:
It's just a normal png image but with some addition markers (the black points/lines on the borders), and Android will use these markers to stretch the image as you want.
For more details about how to use the 9-Patch file, see the official docs.

Related

Shadow resulting from elevation showing with circle drawable as background but not with rectangle

I'm trying to use a View's elevation property to cast a shadow. It works fine when the background is a circle or a rounded rectangle drawable. However, if I use a color or a rectangle drawable as a background the shadow doesn't show.
Simply changing the radius of the rounded rectangle to zero, causes the shadow to disappear. I have tried solutions to similar issues such as adding padding and margin. I added both:
android:clipChildren="false"
android:clipToPadding="false"
to the parent View but that didn't fix the problem either.
I am using the simplest shapes possible:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#color/colorAccent" />
</shape>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="10dp"/>
<solid android:color="#color/colorAccent" />
</shape>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#color/colorAccent" />
</shape>
And here's the very simple layout where I'm testing this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:layout_width="300dp"
android:layout_height="300dp"
android:background="#drawable/rectangle"
android:elevation="40dp"/>
</LinearLayout>
I know there are other ways of achieving shadows in Android such as using 9-patch images, but elevation is a much simpler way and I'm hoping to make it work using only that.
These are the previews changing only the background drawable.
https://i.imgur.com/CtVhI8m.png
https://i.imgur.com/T2Ozcz7.png
This is the end result I'm going for:
https://i.imgur.com/irIMNAF.png
But I mostly just want to figure out why the shadow is not showing with a color or rectangular drawable as background.
When I use a solid color background (e.g. android:background="#fff") or a rectangle shape without rounded corners and run the app, I see a shadow.
However, I have to actually run the app. Just looking at the Android Studio layout preview doesn't show the shadow unless I use a background drawable with rounded corners. So I suspect you're just looking at a bug (or feature?) of the layout preview.
In my case helped wrap my shape with layer-list like this:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/avatar_ripple">
<item>
<shape android:shape="oval">
<solid android:color="#color/black_light" />
<stroke
android:width="#dimen/stroke_large"
android:color="#color/gray" />
</shape>
</item>
Then you can simple apply elevation to your view with your drawable as background, but there is bug that you won't see the shadow until you launch the app.
Particularly helped this answer: https://stackoverflow.com/a/60424218/16006976

Cut a shape from a view in android

I want to cut a transparent oval from a linear layout like below image
any idea?
You cannot cut layouts, instead what you can do is make the circular arrow image transparent by declaring the button opacity like the example given below:
Make an XML file like this:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<!--apply button background transparent, full opacity-->
<solid android:color="#00ffffff"/>
<!--make button border solid color, nontransparent-->
<stroke android:color="#483D8B" android:width="2dp"/>
<corners android:radius="2dp"/>
</shape>
</item>
</selector>
Then simply add this file to your layout:
<Button
android:id ="#+id/push_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button Background Transparent"
android:background="#drawable/button_bg_transparent"
android:padding="15dp"
/>
You will get the result like this:

How to put a horizontal divisor line with depth on the top side

I'm making an activity to my app, and I have to divide some sections of my window with a line. I would like to do something like this:
I only tried with android:elevation="2dp on View in XML layout:
<View
android:layout_width="fill_parent"
android:layout_height="12dip"
android:layout_marginTop="15dp"
android:background="#E0E0E0"
android:elevation="2dp"
/>
But this only put depth on the bottom.
Higher elevation values will also add some shadow at the top of your View.
If you want more "shadow" at the top you can mimic it using a custom XML Drawable with white background and a top border of grey color and really small size (it can also be a gradient if you don't like the solid line):
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Background -->
<item>
<shape android:shape="rectangle">
<solid android:color="#android:color/white" />
</shape>
</item>
<!-- Top "line" -->
<item android:gravity="top">
<shape android:shape="rectangle">
<size android:height="1dp" />
<solid android:color="#ccc"/>
</shape>
</item>
</layer-list>
If it's a ViewGroup you can also add a View with a small height value aligned right to its top with a grey background or gradient. It's simpler, but also a bit dirtier and worse for layout performance.

Incorrect items sizing in layer-list on pre-lollipop

I have a layer-list
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:right="2dp" android:left="2dp" android:bottom="2dp" android:top="2dp">
<bitmap
android:gravity="center"
android:src="#drawable/ic_menu_alert"/>
</item>
<item android:height="10dp" android:width="10dp" android:gravity="right|top">
<shape android:shape="oval">
<size android:height="10dp" android:width="10dp"/>
<solid android:color="#color/navigation_drawer_notification_red_color"/>
</shape>
</item>
</layer-list>
which shows this image
On lollipop and above everything is fine but on pre-lollipop red circle lose all sizing and padding attributes and image looks like this
I was looking for solution about 3 days and found nothing. I was trying to make my own toolbar layout and set to this imagebuuton scaleType="centerInside" but it didn't help. Could anyone help with this issue?
Thanks in advance!
Its best not to mention the height and width attributes in layer-list. When you use this as drawable in let's say an ImageView (the width and height of the ImageView will override the one's mentioned in item/shape).
You can use top, bottom, left, right to align your items in layer-list.
Note: height and width attributes of item is supported only from API 23.
Here is a working example (Tested in Android 7.0 and Android 4.4):
sample.xml
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/menu"
android:left="16dp"
android:right="16dp"
android:gravity="center">
<bitmap
android:src="#drawable/menu_icon" />
</item>
<item
android:top="8dp"
android:left="56dp"
android:right="24dp"
android:bottom="42dp">
<shape android:shape="oval">
<solid android:color="#android:color/holo_red_dark"/>
</shape>
</item>
</layer-list>
main.xml
<ImageView
android:layout_width="72dp"
android:layout_height="72dp"
android:src="#drawable/sample"
android:scaleType="fitCenter"/>
You can also use wrap_content for height & width in ImageView.
So i came up with a workable solution. I have a layer-list drawable in /drawable and /drawable-v21.
The layer-list drawable in /drawable-v21 contains a vector drawable. The layer-list drawable in /drawable contains a .png . It kind of defeats the purpose of using vector drawables but I had to do this to make it work in this one off case.

How to layout view correctly after stroke of background drawable changed?

What I have:
I have a LinearLayout which contains Views with a background Drawable (rectangular shape with rounded corners and a stroke). They act as color selection buttons. Initially the first button has a background with a thicker stroke (4px instead of 1px). Everything is nice (see left side of picture below).
What I want:
However, when I press such a button, I want to remove the thick stroke from the previously selected button and apply it to the actual button. I try it the following way (only a snippet):
// get layout
LinearLayout favoriteColorsLayout = (LinearLayout) findViewById(R.id.favoriteColorsLayout);
// get view at old position, update stroke, invalidate
View view = favoriteColorsLayout.getChildAt(selectedColorButton);
GradientDrawable drawable = (GradientDrawable) view.getBackground();
drawable.setStroke(1, Color.parseColor("#bbbbbb"));
view.invalidate(); // do I need this?
// also update stroke of new view
..
// re-layout
favoriteColorsLayout.requestLayout(); // do I need this?
What I see:
And indeed the thicker stroke is moved but unfortunately the layout is wrong afterwards! The colored background of buttons 2-4 should become thinner when the stroke surrounding them gets thicker so that they are still fitting into the containing layout but this does not happen (see right side of picture below). Instead the stroke is partially cut off (because otherwise it would be drawn outside the bounds of the View). This is not a desired effect.
What do I have to do to get the desired effect instead?
I know how many buttons of which color I have only at runtime, so I would prefer a programmatic solution.
Actually I'm beginning to think it could be an Android bug since drawing the stroke outside the borders per default is surely not desired behavior. I see the effect on the emulator and API level 23 as well as my old phone with API level 11.
A bit of layout xml. The linear layout (Views are added programmatically):
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:id="#+id/favoriteColorsLayout"></LinearLayout>
The button Views:
<?xml version="1.0" encoding="utf-8"?>
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="#dimen/color_selection_button_size"
android:layout_height="#dimen/color_selection_button_size"
android:layout_margin="#dimen/color_selection_button_margin"
android:layout_gravity="center"
android:background="#drawable/color_selection_cell_background">
</View>
The buttons background drawable (color_selection_cell_background.xml):
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<stroke
android:width="1px"
android:color="#bbbbbb"/>
<corners
android:radius="5px" />
<gradient
android:angle="90"
android:centerX="0.5"
android:centerY="0.5"
android:startColor="#aaaaaa"
android:endColor="#bbbbbb"
android:type="linear" />
</shape>
Not sure why you are doing it in code but why not have two drawables and change those?
button_blue_selected.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/blue_500" />
<stroke android:width="4dp" android:color="#color/grey_500" />
<corners android:radius="5dp" />
</shape>
button_blue_unselected.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/blue_500" />
<stroke android:width="1dp" android:color="#color/grey_500" />
<corners android:radius="5dp" />
</shape>
Then update the background drawable in your code:
View view = favoriteColorsLayout.getChildAt(selectedColorButton);
view.setBackgroundResource(R.drawable.button_blue_selected);
Or even better you could use a third drawable with state so you didn't need to update it directly in code:
button_blue.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="#drawable/button_blue_selected" />
<item android:drawable="#drawable/button_blue_unselected" />
</selector>
And then:
view.setSelected(true);

Categories

Resources