I'm trying to simplify some graphics from requiring a 9-patch for each density, to just using an XML drawable. It's a fairly simple graphic:
2 Segments:
8dp wide for both segments
Top segment is 2dp tall
Bottom segment fills the view
Right side is filled with transparency
Giving this result when set as a background image:
It seems like this should be fairly simple to recreate as an XML drawable, and would avoid creating 5 different 9-patch graphics. However, I've looked into layer-list drawables, inset drawables, clip drawables -- they all seem to require that you know the size of the view beforehand (e.g. to keep it 2dp for an inset, you'd need to set insetRight to the width of the view - 2dp). I also tried using the shape tag's size tag, but that doesn't keep a fixed size, just a fixed proportion (so for taller views it will scale proportionally).
Am I overlooking something simple, or is this something I'd have to resort to checking programatically after layout?
This is not possible. This is the best solution I found. Only xml, no coding, no bitmaps, no additional views )
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="#ff0000" />
</shape>
</item>
<item
android:top="4dp">
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="#00ff00" />
</shape>
</item>
<item
android:left="10dp">
<shape
android:shape="rectangle">
<solid
android:color="#FFFFFF" />
</shape>
</item>
</layer-list>
Via code you can make your own drawble type with desired behavior. Xml drawable very limited. IMHO my suggestion is the closest to what you demanded.
I think the answer by #Leonidos is very close to what I'm proposing, except I'm using the drawable as a separate view instead of the background for the entire list detail layout. This allows it to be a fixed width and to let the item text have its own background. Let me know if I'm not understanding your constraints.
The following file is "res/drawable/list_left_border"
<?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="#e76e63" />
</shape>
</item>
<item android:top="2dp">
<shape android:shape="rectangle" >
<solid android:color="#ffc257" />
</shape>
</item>
</layer-list>
Then on the layout for the list item in "res/layout/list_item.xml"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity" >
<View
android:background="#drawable/list_left_border"
android:layout_width="8dp"
android:layout_height="match_parent" />
<TextView
android:id="#+id/listItemText"
android:textSize="15sp"
android:padding="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Here's the image. The background is pink to show that the list item is transparent.
I'm going to go one further and suggest a slight reworking of AndroidGuy's answer, which itself includes Leonidos' answer.
Same drawable XML, different list item XML as follows:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="100sp">
<ImageView
android:layout_width="8dp"
android:layout_height="match_parent"
android:src="#drawable/list_left_border" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="Item Text"
android:textSize="22sp" >
</TextView>
</FrameLayout>
The FrameLayout gives the original background behaviour, rather than separation into a new view.
I've shown this below, with backgrounds to demonstrate:
This doesn't really deserve the points though.
Related
I want to fill only top half of my screen with below gradient
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:bottom="500sp">
<shape android:shape="rectangle" >
<corners
android:bottomLeftRadius="40sp"
android:bottomRightRadius="40sp" />
<gradient
android:startColor="#9CA0DD"
android:endColor="#ECB8B8"
android:angle="270" />
</shape>
</item>
</layer-list>
xml for layout
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/home_background_color">
</ScrollView>
This works fine with large screen devices but not with smaller screen , I am using "sp" instead of "dp" but the result is same
Try a different approach, since there is no way to specify a percentage in a drawable.
What you can do is to place a View behind the ScrollView, dedicated exclusively to the background. And use a Constraintlayout as your main one for more flexibility.
So for your drawable would be as next (notice it must be all in DPs and not SPs, and that your 'android:bottom=500sp' is fully removed):
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners
android:bottomLeftRadius="40dp"
android:bottomRightRadius="40dp" />
<gradient
android:startColor="#9CA0DD"
android:endColor="#ECB8B8"
android:angle="270" />
</shape>
</item>
</layer-list>
For the main layout must be as next, (notice the tag 'app:layout_constraintHeight_percent="0.5"'):
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="match_parent"
android:background="#FF303030"
tools:context=".MainActivity">
<View
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.5"
android:background="#drawable/home_background_color" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
The result is next:
As a side note, use the "sp" units only for fonts and never for graphics, for anything else that isn't a font (text size) use always "dp" units.
I have a circular ImageView as you can see below, this references a vector drawable, I would like to fill the inside of the circle with another View, without having that rectangle outside the circle, is this possible in any way?
<FrameLayout
android:layout_gravity="center_horizontal"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="#android:color/black"
>
<com.myapp.MySpecialBackground
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/icon"
android:tint="#color/blue"/>
</FrameLayout>
You can use a ShapeDrawable as background resource. Add a drawable resource file to your project and set the "padding" so the circular shape will not show outside of your blue circle:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<padding
android:left="30dp"
android:top="30dp"
android:right="30dp"
android:bottom="30dp" />
<size
android:width="150dp"
android:height="150dp" />
<solid android:color="#ff0000"/>
</shape>
I used 30dp but that's hard to tell from your screenshot, so most likely you'll have to experiment. Just keep in mind that you'll get a circle if your ImageView is a square and all padding values are equal.
(For older android versions: the size tag is relatively new, in earlier versions the width and height attributes went into the shape tag)
I am trying to create a button, aligned to the bottom of the page. I want it to fill 100% space, from left, right and bottom. Whatever attributes I will choose, there are still very small non covered areas. Can you please help?
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="match_parent"
tools:context="com.example.myapplication.MainActivity">
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_margin="0dp"
android:padding="0dp"
android:text="search"
/>
</RelativeLayout>
Here is the screenshot, showing not filled areas
Create a file in drawable folder like this, say simple_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape android:shape="rectangle">
<!-- Normal color -->
<solid android:color="#android:color/white" />
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<!-- Color - when the view is pressed -->
<solid android:color="#android:color/black"/>
</shape>
</item>
</selector>
Now simply set the background as the above created drawable.
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:background="#drawable/simple_selector"
android:text="search"
/>
The above code can change color in both normal and pressed states of the button. You can change the colors as per your requirement.
The space you see is the shadow around the button in its background drawable. You need to create your own background drawable and it should then completely occupy the width.
Or, you could also just set the background to null.
android:background="#null"
I'm trying to use a listView with a divider and I was about to change divider's width so I looked in the web site and I found this solution :
Listview divider margin
When I tested in my app, I have no divider, but if I switch to use a simple color the divider appears again
This this my code :
my Activity layout :
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="80sp"
android:elegantTextHeight="true"
android:text="Paramètres"
android:textSize="24sp"
android:gravity="center"
android:textColor="#ffffff"
android:background="#191919"/>
<ListView
android:id="#+id/list"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:dividerHeight="2dp"
android:divider="#drawable/list_divider">
</ListView>
</LinearLayout>
list_divider.xml
<?xml version="1.0" encoding="UTF-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="15dp"
android:insetRight="15dp" >
<shape
android:shape="rectangle" >
<stroke
android:dashGap="1dp"
android:dashWidth="1.5dip"
android:width="2dp"
android:color="#000000" />
<size android:height="3dp"/>
</shape>
</inset>
You are giving wrong file name to your divider attribute.Change this line
android:divider="#drawable/list_devider"
To
android:divider="#drawable/list_divider"
because your list divider drawable file name is list_divider not list_devider
And I will suggest you to use px as a dividerHeight instead of dp
if you specify 1dp or 1dip, Android will scale that down. On a 120dpi device, that becomes something like 0.75px translated, which rounds to 0. On some devices, that translates to 2-3 pixels, and it usually looks ugly or sloppy
For dividers, 1px is the correct height if you want a 1 pixel divider and is one of the exceptions for the "everything should be dip" rule. It'll be 1 pixel on all screens. Plus, 1px usually looks better on hdpi and above screens
So I modified my listdivide.xml file to that, the it work :
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="16dp"
android:insetRight="16dp">
<shape>
<solid android:color="#000000" />
<corners android:radius="1dp" />
</shape>
</inset>
But i still don't know why the first dosn't work :)
I am trying to put two oval drawables on top of each other, the first has transparency. However with the way I have it, it displays the first oval's color at the size of the second oval.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="oval">
<size android:width="15dp" android:height="15dp" />
<solid android:color="#35000000"/>
</shape>
</item>
<item>
<shape android:shape="oval">
<size android:width="5dp" android:height="5dp" />
<solid android:color="#000000"/>
</shape>
</item>
</layer-list>
How can I get this to work as intended?
EDIT:
Here is the parent:
<?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="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/my_layerlist" />
</LinearLayout>
After doing much research on the different types of XML drawables, it appears that your LayerDrawable (layer-list) is be scaling the ShapeDrawables independently. Then, the ImageView is scaling the LayerDrawable. According to this guide from Google, scaling for both ShapeDrawables and LayerDrawables is a concern. LayerDrawables will check for necessary scaling on each item you have. They have several solutions:
Set the gravity to something that does not scale, such as "center".
define the drawable as a bitmap.
Set the ImageView to scaleType that does not scale.
There is two major problem with this, however... You can only use gravity for the bitmap. And you cannot use a ShapeDrawable for the bitmap in XML. I tried everything I could think of to get it right. Here's the only thing that fixed it for me.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imageView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/oval1"
android:scaleType="center" />
<ImageView
android:id="#+id/imageView2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/oval2"
android:scaleType="center" />
</FrameLayout>
So: I removed the LayerDrawable, separated the Shapes into their own XMLs, made two ImageViews. (for ease I stuck them in a FrameLayout). This was the only way to stop the scaling.
Testing Procedure
Tested in Android 2.1, 3.0, 4.0
Changed Image scaleType
Changed Image width and height
Separated ShapeDrawables
Changed LayerList to just items with drawable attribute referencing separated shapes
Changed LayerList to bitmaps referencing separated shapes.
Changed order of shapes
Alternatively, you could do it in code.
Reference: Drawable Resources