Adding multiple LayerList to API 19 Device causing inflating error
Asked Answered
C

4

6

I'm trying to create a Button with two backgrounds, my custom background

android:background="@drawable/background_profile_edit_button" + ?attr/selectableItemBackground```

Full button:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintTop_toBottomOf="@+id/fragprofile_constraint"
    app:layout_constraintRight_toRightOf="parent"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="16dp"
    android:background="@drawable/background_profile_edit_button"
    android:paddingStart="32dp"
    android:paddingTop="6dp"
    android:paddingEnd="32dp"
    android:paddingBottom="6dp"
    android:text="Edit Profile"
    android:textColor="@color/colorBlackFont"
    android:textSize="12sp"
    android:textStyle="bold"/>

This can be easily fixed with android:foreground="?attr/selectableItemBackground" however that requires api 23 and my min is 19.

I have also tried another approach using layer-list in my drawable:

<?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/colorWhite" />

            <stroke
                android:width="1dp"
                android:color="@color/dividerColor" />
            <corners android:radius="3dp"/>
        </shape>
    </item>

    <item
        android:drawable="?attr/selectableItemBackground">
    </item>


</layer-list>

This layerlist works perfectly on my higher API devices. However it's causing a crash on my API 19 device...

android.view.InflateException: Binary XML file line #201: Error inflating class TextView

This person also has had the same problem and it's also unanswered:

LayerList error API 19: tag requires a 'drawable' attribute or child tag defining a drawable

TLDR:_______________________________________________________

enter image description here

Doing this on a API 19 Device

Candace answered 15/3, 2020 at 8:34 Comment(0)
C
3

Right now I'm just using a RelativeLayout as a wrapper for the button. If someone has a solution without a NestedLayout Hacky Solution that would be great.


<RelativeLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:id="@+id/fragprofile_edit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/background_profile_edit_button">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="?attr/selectableItemBackground"/>
    </RelativeLayout>

</RelativeLayout>

Edit: An issue with this problem is that the android:background="@drawable/background_profile_edit_button" on the Relative layout causes corner radius to not work... on devices less than API 21...

https://mcmap.net/q/63954/-how-to-make-layout-with-rounded-corners

Candace answered 19/3, 2020 at 2:27 Comment(0)
R
1

The Context.getDrawable(Theme) and Resources.getDrawable(int,Theme) were both introduced in Android SDK level 21. Before themed attributes were not supported in drawable resources. There was just no Theme available to load the attributes from.

The blog post Styling Colors & Drawables w/ Theme Attributes by Alex Lockwood explains it even better.

Resistencia answered 17/3, 2020 at 21:30 Comment(0)
F
1

Have you tried referencing the drawable directly in your layer-list instead of referencing the stylable attribute (following @tynn's answer)? did it work? or is there a reason why this wouldnt work for you?

If the layers list works on all API's except 19 there is one workaround/compromise I could suggest. leave you current layer-list as it is in the drawable folder as well as in drawable-v21 (you might need to create this folder) and then create an alternative button design that works on API19 and save it in drawable-v19 maybe your app wont look as nice in API19 but at least it will still run without errors on all devices.

this works by telling android that it should use a different drawable resource whenever it encounters API19 you can read more about it here. android will automatically take its resource from the dawable-vXX folder that is closest to its API and revert to the drawable folder if it cant find the resource in that drawable-vXX folder.

There is also this article that I found of someone also obsessed with this. apparently you could try replacing your textview with a button and achieve the ripple effect using an AppTheme

<!-- styles.xml -->
<style name="AppTheme.YellowButton">
    <item name="colorButtonNormal">@color/yellow</item>
</style>

<!-- layout.xml -->
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.YellowButton"
android:text="Yellow Tint Button" />

let me know if it works

Forme answered 18/3, 2020 at 22:50 Comment(3)
Yes I've tried referencing the drawable directly. On higher API device 28 it works. On my API 19 device it just completely crashes on startup.Candace
it seems like someone has already asked the same question and someone else already gave my anwser as well XD https://mcmap.net/q/494097/-selectableitembackground-as-item-in-layer-list apparently there is no solution below api21 so you could try my compromiseForme
if I understand correctly you want your button to change color when clicked. maybe you can write some java code to do that for api19 or simply use my approach create folders drawable-v19 and drawable-v21 and live with the fact that the small % of your users still using api19 will not get to enjoy that animationForme
F
0

You can do it in code. Try code below:

// rect.xml file in drawables
<?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" />

    <stroke
        android:width="1dp"
        android:color="@android:color/holo_green_light" />
    <corners android:radius="3dp" />
</shape>


fun getLayer(id: Int) = if (android.os.Build.VERSION.SDK_INT < 21) resources.getDrawable(id)
else resources.getDrawable(id, theme)

// Get first shape layer
val layer1 = getLayer(R.drawable.rect)

// Get second layer from  attributes
val a = theme.obtainStyledAttributes(
    R.style.AppTheme,
    intArrayOf(android.R.attr.selectableItemBackground)
)
val attributeResourceId = a.getResourceId(0, 0)
val layer2 = getLayer(attributeResourceId)

// Create layer list
val layers = LayerDrawable(arrayOf(layer1, layer2))

button.background = layers
Flagler answered 24/3, 2020 at 13:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.