2

I'm trying to learn how to use custom attributes in Android Studio. I follow a couple of tutorials on the subject and despite my efforts nothing seems to work. I created a code that illustrates the problem.

I've created simple custom view, which doesnt represent anything but only obtains styled attributes. This is my customView code:

package com.example.mytestattributes;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;

import androidx.annotation.Nullable;

public class customView extends View {
    public customView(Context context) {
        super(context);
        init(null);
    }

    public customView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }
    private void init(@Nullable AttributeSet attrs){
        if(attrs!=null){
            Log.d("INIT", "attribute set found");
            TypedArray ta = getContext().obtainStyledAttributes(R.styleable.customView);
            Log.d("LENGHT OF TA: ", ta.length()+"");
            Log.d("testString has value", ta.hasValue(R.styleable.customView_testString)+"");
            Log.d("testInteger has value", ta.hasValue(R.styleable.customView_testInteger)+"");
            Log.d("testBoolean has value", ta.hasValue(R.styleable.customView_testBoolean)+"");
            Log.d("testColor has value", ta.hasValue(R.styleable.customView_testColor)+"");
            Log.d("testDimension has value", ta.hasValue(R.styleable.customView_testDimension)+"");
            Log.d("testEnum has value", ta.hasValue(R.styleable.customView_testEnum)+"");

            Log.d("Return testDimension: ", ""+ta.getDimensionPixelSize(R.styleable.customView_testDimension,0));
            Log.d("Return testDimension: ", ""+ta.getDimension(R.styleable.customView_testDimension,0));

        }else{
            Log.d("INIT", "no attribute set found");
        }


    }
}

The code compiles and the output is:

D/INIT: attribute set found
D/LENGHT OF TA:: 6
D/testString has value: false
D/testInteger has value: false
D/testBoolean has value: false
D/testColor has value: false
D/testDimension has value: false
D/testEnum has value: false
D/Return testDimension:: 0
D/Return testDimension:: 0.0

The lenght of typed array is correct, meaning that the program sees the attributes but when I ask it to check if the attributes have value the outcome is false. As a consequence any attempt to read this attibutes always returns default value. In the example code I included just getDimension but the same holds for all other get methods.

This is my attrs.xml, where I defined the attibutes:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="customView">
        <attr name="testString" format="string|reference"/>
        <attr name="testInteger" format="integer"/>
        <attr name="testBoolean" format="boolean"/>
        <attr name="testColor" format="color|reference"/>
        <attr name="testDimension" format="dimension"/>
        <attr name="testEnum" format="enum">
            <enum name="var1" value="1"/>
            <enum name="var2" value="2"/>
        </attr>
    </declare-styleable>
</resources>

I try to pass values in Activity_Main.xml:

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

    <com.example.mytestattributes.customView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:testBoolean="true"
        app:testDimension="200dp"
        app:testColor="@color/colorAccent"
        app:testEnum="var1"
        app:testInteger="15"
        app:testString="@string/app_name"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

The MainActivity.java is unmodified empty activity class. I am aware that some people had the similiar problems a couple of years ago but no valid answers were ever posted. Is anyone aware what is wrong with this code? Im using API 17.

2
  • Why haven't you declared reference as one of your attribute formats when you're passing resources? <attr name="testString" format="string|reference"/> for strings and <attr name="testColor" format="color|reference"/> for colors. Commented May 3, 2020 at 12:49
  • I modified the code according to your suggenstion but it does not change anything. The output is still false. Commented May 3, 2020 at 18:26

1 Answer 1

3

After some tinkering I replaced the line:

TypedArray ta = getContext().obtainStyledAttributes(R.styleable.customView);

with

TypedArray ta = getContext().obtainStyledAttributes(attrs,R.styleable.customView);

and the problem was solved. Alternatively I also found out that if the TypedArray ever failed me again it is possible to get values directly from attrs, with:

attrs.getValue(int index) 

It must be noted that the index of the attribute in the attribute set is different than the index in the typed array, as it includes also standard android attributes. The index can be checked with:

            for (int i = 0; i < attrs.getAttributeCount(); i++) {
                Log.d("ATTRS", i+ ": " + attrs.getAttributeName(i)+"");
            }
Sign up to request clarification or add additional context in comments.

1 Comment

Getting values from attrs directly saved my day, thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.