I try to implement the Material Design's elevation concept to my RecyclerView.
For each item of the RecyclerView I use this
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
card_view:cardCornerRadius="0dp"
android:elevation="2dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<TextView
.../>
<CheckBox
.../>
</RelativeLayout>
</android.support.v7.widget.CardView>
When I select item, I apply programmatically a drawable to the background for effect, and I set the elevation to 8dp as advised by Material Design specifications.
val draw = ResourcesCompat.getDrawable(resources, R.drawable.selected_task, null)
draw?.setColorFilter(task.color.aRGB.toInt(), PorterDuff.Mode.OVERLAY)
view.background = draw
view.elevation = 8F
(I code in Kotlin)
The drawable:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="2dp"
android:color="#color/select_border"/>
<solid
android:color="#color/select_fill"/>
</shape>
and the colors values
<color name="select_border">#78000000</color>
<color name="select_fill">#32000000</color>
The problem is when I select one item, the drawable is nicly applied but the shadows are tottaly removed and not amplified !
And if I not set the background with the drawable, it's works well. The shadows are amplified like expected.
What is the problem ?
It is trouble from 2014 https://issuetracker.google.com/issues/37008403
Decision 1
Do not use colors with transparency for background CardView
Decision 2
Set background for View or ViewGroup inside the CardView instead of this cardView, then everything works correctly
Related
This is my drawable shape
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<corners android:topLeftRadius="20dp"
android:topRightRadius="20dp"
android:bottomLeftRadius="20dp"
android:bottomRightRadius="60dp"/>
<solid android:color="#color/primary_blue"/>
</shape>
My layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="296dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:clipChildren="true"
android:clipToPadding="false"
android:background="#drawable/bg_shape_bottom_right_curved"
app:cardPreventCornerOverlap="false"
android:outlineProvider="background"
android:layout_height="198dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/phase_banner"
android:scaleType="centerCrop"
android:adjustViewBounds="true"/>
</LinearLayout>
The image keeps on being square and not getting the shape of drawable. Please help
When i add shape to the layout its showing the shape . But when i set image src its showing sqaure image , when setting background, it getting into right shape. But i need to load image from glide . so i need to make it work with src
Unfortunately, your background drawable does not qualify for clipping. From Clip Views:
Only rectangle, circle, and round rectangle outlines support clipping, as determined by the Outline.canClip() method.
Your background drawable does not qualify as a rounded rectangle but is implemented internally as a path (I believe). This is one reason clipping is failing for you.
Let's create a simple rounded rectangle drawable:
simple_rounded_rectangle.bg
<shape android:shape="rectangle" >
<corners android:radius="30dp"/>
<solid android:color="#color/primary_blue"/>
</shape>
Also, let's modify the layout a little:
activity_main.xml
<LinearLayout
android:id="#+id/layout"
android:layout_width="400dp"
android:layout_height="198dp"
android:background="#drawable/simple_rounded_rectangle"
android:outlineProvider="background">
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="#drawable/phase_banner" />
</LinearLayout>
We will also need to add some code to direct the view system to clip the view to the outline:
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val layout = findViewById<LinearLayout>(R.id.layout)
layout.clipToOutline = true
}
}
The main thing in this code is the line
layout.clipToOutline = true
which indicates that clipping should occur. There should be an XML attribute that does the same thing android:clipToOutline but there isn't below API 31. See the android:clipToOutline bug report.
Putting it altogether we see the following. (The image is one I supplied.)
If you use your drawable for the background, it will not be clipped for the reason I mentioned above.
You will need to fall back to a different method of clipping if you need asymmetric corners on your drawable. You may want to look at applications of clipPath. You will find information on how to do this if you do some online searching. I also suggest the Medium post Clipping and shadows on Android for other alternatives.
Take a look at the Material Components Library. MaterialCardView and ShapeableImageView may be useful.
This is your drawable shape.
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:topLeftRadius="20dp"
android:topRightRadius="20dp"
android:bottomLeftRadius="20dp"
android:bottomRightRadius="20dp"
/>
<solid android:color="#color/primary_blue"/>
</shape>
Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="400dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:clipChildren="true"
android:clipToPadding="false"
app:cardPreventCornerOverlap="false"
android:outlineProvider="background"
android:layout_height="198dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/phase_banner"
android:src="#drawable/XYZ"
android:scaleType="centerCrop"
android:adjustViewBounds="true"/>
</LinearLayout>
Try this you want like this?
I want to make my ImageView curved at the bottom with shadow effect.
Similar to this image
But I don't have any idea about how to do this.
Whenever I search on Google or StackOverflow it shows me results related to curved corners but I want curved edge at bottom.
you can make shape use layer-list
for example,
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:left="-150dp"
android:right="-150dp"
android:top="-200dp">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#C72C2F" />
</shape>
</item>
</layer-list>
it show like this.
And then use this in background,
<?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"
tools:context=".MainActivity">
<LinearLayout
app:layout_constraintTop_toTopOf="parent"
android:background="#drawable/round"
android:elevation="30dp"
android:layout_width="match_parent"
android:layout_height="700dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
it make like this.
Also for make shadow effect, I use android:elevation it make shadow, and if you increase value, it can make more depth.
And obviously add image view for show images. I believe you can do this.
I want to re-create the image below with a CardView. To achieve this, I created a gradient file (btn_gradient.xml) and then proceeded to create the CardView.
CardView implementation:
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_margin="25dp"
app:cardElevation="0dp"
app:cardCornerRadius="4dp"
app:cardPreventCornerOverlap="false">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="#drawable/btn_gradient"
android:text="Create Account"
android:textColor="#000000"
android:textStyle="bold"
android:textAllCaps="false"/>
</android.support.v7.widget.CardView>
Everything works fine this way except that the radius disappears and this is not what I want. Is there a way I can set the gradient directly on the CardView? The cardBackgroundColor attribute accepts only colors, not drawables.
Any help would be appreciated.
Addendum: As requested, this is my btn_gradient.xml file:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:type="linear"
android:angle="0"
android:startColor="#ffc200"
android:endColor="#fca10b" />
</shape>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/_10sdp"
app:cardCornerRadius="#dimen/_10sdp"
app:cardElevation="#dimen/_1sdp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#drawable/gradient_16"
android:padding="#dimen/_6sdp">
</LinearLayout>
</androidx.cardview.widget.CardView>
and gradient be like
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#5B86E5"
android:endColor="#36D1DC"
android:angle="180" />
<corners
android:radius="10dp">
</corners>
</shape>
CardView card_radius and gradient radius should be same dimentions
If I may ask, are you per-chance testing/running on a pre-lollipop Android device? Your code seems to work as you desire (curved corners showing with the gradient) except on Android 4.
To achieve the desired result on pre-lollipop devices, you can add <corners android:radius="4dp" /> to your #drawable/btn_gradient file, (you would have to set the corner radius to match the CardView's cardCornerRadius.
Move this line
android:background="#drawable/btn_gradient"
To the CardView object
UPDATE
My bad:
Inside the place a layout to wrap the content of the .
In this case, I'd go with a <FrameLayout> like this:
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLyout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/btn_gradient">
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#004e92"
android:endColor="#614385"
android:angle="90" />
<corners
android:topRightRadius="10dp"
android:bottomLeftRadius="10dp"
android:bottomRightRadius="10dp"
android:topLeftRadius="10dp">
</corners>
</shape>
[![enter image description here][1]][1]
<LinearLayout 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:orientation="vertical"
android:layout_height="match_parent"
android:background="#drawable/color"
tools:context=".MainActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="10dp"
app:cardCornerRadius="10dp"
android:layout_height="100dp">
<LinearLayout
android:layout_width="match_parent"
android:background="#drawable/cardcolor"
android:layout_height="100dp">
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
</ScrollView>``
</LinearLayout>
[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/iewIm.png
[1]: https://i.stack.imgur.com/pHIlW.png
I've tried integrating the gradient on card view dynamically & faced the issue that the corner radius got impacted that was set on the view property in xml file like app:cardCornerRadius="#dimen/margin_20".
Solution :
Implementing the gradient on card view. I'm getting 2 gradients from api that will be incorporated from left to right.
` try {
val startColor = sample?.gradient1
val endColor = sample?.gradient2
val colors =
intArrayOf(Color.parseColor(startColor),
Color.parseColor(endColor))
val gradientDrawable = GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT, colors
)
myCardView.background = gradientDrawable
} catch (e: Exception) {
// default color to white
myCardView.setBackgroundColor(
ContextCompat.getColor(
mContext,
R.color.white
)
)
}`
Now on running the code, the card view renders with the gradient value but the issue occurs with the corner radius of card view that was set statically at xml. The corner radius got removed. To solve the issue, we simply use to set the radius of the gradient drawable that holds the drawable color in gradient form. Just add below 3 lines before setting the background.
gradientDrawable.colors = colors
// setting the corner radius on gradient drawable
gradientDrawable.cornerRadius = 40f
myCardView.background = gradientDrawable
The final code with gradient configuration & setting the corner radius is :
try {
val startColor = sample?.gradient1
val endColor = sample?.gradient2
val colors =
intArrayOf(Color.parseColor(startColor),
Color.parseColor(endColor))
val gradientDrawable = GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT, colors
)
gradientDrawable.colors = colors
// setting the corner radius on gradient drawable
gradientDrawable.cornerRadius = 40f
myCardView.background = gradientDrawable
myCardView.background = gradientDrawable
} catch (e: Exception) {
// default color to white
myCardView.setBackgroundColor(
ContextCompat.getColor(
mContext,
R.color.white
)
)
}`
Screenshot for better view of code :
Hope this will help. Happy Coding :) Cheers!
Do not use android:background attribute in XML file.
use app:cardBackground instead.
To wrap it up, first create a gradient background XML file in drawables.
then assign it to the app:cardBackgroundColor like this:
app:cardBackgroundColor="#drawable/gradient_background"
if you don't know how to create the gradient_background.xml, write click on drawables directory, create new xml file and paste the code below.
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle"
xmlns:android="http://schemas.android.com/apk/res/android">
<gradient android:startColor="#color/secondaryColor"
android:endColor="#color/primaryColor"
android:angle="90"/>
</shape>
I have a LinearLayout view to which I need to set the background image programmatically. However, when this view gets the focus, I need to show a stroke around it.
What am I doing:
The background resource (view_onfocus_background.xml) to show onFocus effect:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true">
<shape android:shape="rectangle">
<stroke android:width="5dp" android:color="#F7CA18" />
</shape>
</item>
</selector>
In the layout XML, I am adding the background as follows to apply the background with onFocus effect.:
android:background="#drawable/view_onfocus_background"
However, in the code, I have to set the different background image to the layout.
myLayout.setBackgroundResource(R.drawable.custom_image);
So, obviously, the view_onfocus_background I added in the layout XML doesn't apply anymore!
Question:
How can I achieve onFocus effect as well as custom image background to the layout?
I figured out that there is no way I can apply background effect through XML as well as the image background to the LinearLayout. The only thing I could do is to have two LinearLayouts (parent and child). Apply XML to the parent layout. Apply image background to the child layout. Add some padding in the parent layout to show the onFocus effect.
Example:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/customFocusLayout"
android:padding="5dp"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:clickable="true"
android:focusable="true"
android:orientation="vertical"
android:background="#drawable/view_onfocus_background"
>
<LinearLayout
android:id="#+id/customTestLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="false"
android:padding="0dp"
android:layout_gravity="bottom"
android:background="#drawable/custom_image"
android:orientation="vertical">
<!-- more stuff here-->
</LinearLayout>
</LinearLayout>
I have a LinearLayout that looks like this.
I want each row to be clickable. The LinearLayout code for a row looks like this:
<LinearLayout
style="#style/home_menu_item_container"
android:id="#+id/home_menu_acronyms_button"
>
<ImageView
style="#style/home_menu_item_left"
android:background="#color/greyLight"
/>
<TextView
style="#style/home_menu_item_right"
android:text="#string/home_menu_option_2"
android:background="#color/grey"
/>
</LinearLayout>
How can I add a ripple effect that expands over the entire row (parent) - not just one child view in the row? The tricky part here is to let the ripple go over the two colored row.
So far, I found out the easiest way to do so is define a <ripple> in your drawable and then set the background of the LinearLayout to this drawable resource.
Define your drawable-v21/item_selector.xml
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/your_background_color">
<item android:id="#android:id/mask"
<!--color here doesn't matter-->
android:drawable="#android:color/white" />
</ripple>
Set the background of your LinearLayout to drawable/item_selector.
<LinearLayout
style="#style/home_menu_item_container"
android:background="#drawable/item_selector"
android:id="#+id/home_menu_acronyms_button" >
...
</LinearLayout>
Besides, if you don't have your own background color, then there is no need to define a item_selector at all. You can simply define background as android:background="?android:attr/selectableItemBackground" for your LinearLayout.
It is a little bit complicated for that what you need but I don't think there is another way,...
You need to put your ImageView's into a ListView so that every ImageView is a ListItem and then you can set the ripple but you also need to set drawSelectorOnTop="true" otherwise it won't work correctly
I too faced this problem, finally found a simple solution
In linear Layout just add android:clickable="true";
and set background with ur ripple effect as
android:background="#drawable/ripple_effect"
code:
<LinearLayout
android:clickable="true"
android:background="#drawable/ripple_effect"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Add your child views here -->
</LinearLayout>
add ripple_effect.xml in drawable
ripple_effect.xml:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:color="#f87d05c2"
tools:targetApi="lollipop">
<item android:id="#android:id/mask">
<shape android:shape="rectangle">
<solid android:color="#f87d05c2" />
</shape>
</item>
</ripple>
<RelativeLayout
android:id="#+id/rll_privacy_policy"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackground"
android:orientation="vertical">
<TextView
android:id="#+id/txt_privacy_policy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/layout_margin_16"
android:text="#string/privacy_policy"
android:layout_centerVertical="true"
android:textColor="#color/link_acc"
android:textSize="#dimen/txt_title_20" />
</RelativeLayout>
Another option is to make the ripple's background color transparent. This way only the ripple can be seen. The ripple's xml file (in your drawable-v21/ folder) is thus:
<-- Ripple in some ghastly color, like bright red so you can see it -->
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/red"
>
<!-- background color uses a transparent mask set to full #ffffff (white) -->
<item
android:id="#android:id/mask"
android:drawable="#android:color/white"
/>
Note that if you are supporting pre-lollipop devices, you need to have a dummy file with the same name in your drawable/ folder. An empty selector is sufficient for that file. And remember that those older devices will not ripple.
answer above dont work for me,
here is my solution:
ripple.xml:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight">
<item android:id="#android:id/mask">
<shape android:shape="rectangle">
<solid android:color="?android:colorAccent" />
</shape>
</item>
</ripple>
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
>
...put het your design
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/ripple" />
</FrameLayout>