How to use standard attribute android:text in my custom view?
use this:
public YourView(Context context, AttributeSet attrs) {
super(context, attrs);
int[] set = {
android.R.attr.background, // idx 0
android.R.attr.text // idx 1
};
TypedArray a = context.obtainStyledAttributes(attrs, set);
Drawable d = a.getDrawable(0);
CharSequence t = a.getText(1);
Log.d(TAG, "attrs " + d + " " + t);
a.recycle();
}
i hope you got an idea
How to support tools:text in a new custom view ?
If you want to use existing tools:
attributes in you custom views, all you have to do is to add those attributes to your <declare-stleable>
:
<declare-styleable name="CustomView">
<!-- This will allow you to use tools:text attribute as well -->
<attr name="android:text"/>
</declare-styleable>
In your custom view you can get the attribute like this:
a.getText(R.styleable.CustomView_android_text)
Now you can do this:
<com.myapplication.CustomView
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Lorem ipsum"/>
This will allow you to use standard tools:
attributes in your custom views. If you'd like to define your own design-time attributes, I've written a small library that allows you to do that.
How to get android default attributes in a custom view
You can add android:text
to your declared syleable. But be sure to not redeclare it.
<declare-styleable name="CustomEditText">
<attr name="android:text" />
</declare-styleable>
And then get this value from the style like you would with any other of your attributes with the index of R.styleable.CustomEditText_android_text
.
CharSequence text = typedArray.getText(R.styleable.CustomEditText_android_text);
Custom view custom attribute not being set without @{}
Mike's comments answer the confusion I had about the different syntaxes.
What I ended up doing ultimately is to inherit the existing android TextView. TextView has a bunch of stuff I needed like font, font size etc, so it was just simpler to inherit rather than re-implement it myself.
Android Custom View with custom Attributes
Change your define <attr name="firstName" format="reference"/>
And in your code use int firstNameViewID = a.getResourceId(attr, -1);
Hope this help!
Default attribute values for my custom view (inherited from LinearLayout)
Similar problem has been solved at https://stackoverflow.com/a/25982512/3554436
Add android:layout_margin
to attrs.xml
<declare-styleable name="PersonView">
...
<attr name="android:layout_margin" />
...
</declare-styleable>
Access the attribute like other custom attributes:
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PersonView);
float margin = a.getDimension(R.styleable.PersonView_android_layout_margin, 0);
...
boolean hasMargin = a.hasValue(R.styleable.PersonView_android_layout_margin);
Is it possible in Android to add a custom view composed of standard views and use it in code but have the layout know only about the standard views?
I would use Custom Attributes.
Imagine you have a "Custom View" that takes a title and an image. You could add to your attrs.xml
the following:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomView">
<attr name="title" format="string|reference" />
<attr name="android:drawable" />
</declare-styleable>
</resources>
You'd then implement this custom view in Code:
(something like this... keep in mind this is "pseudo code", I took it from a custom view I have, but it's greatly simplified for the purposes of this...)
In this custom view, I can supply a title and an image, and will also use a custom background (not included in the demo) :)
class MyCustomView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
@AttrRes defStyle: Int = 0
) : ConstraintLayout(context, attrs, defStyle) {
private val title: MaterialTextView
private val image: ImageView
init {
View.inflate(context, R.layout.HERE_GOES_THE_LAYOUT, this).also {
title = it.findViewById(R.id.title)
image = it.findViewById(R.id.image
// set some properties (just an example)
it.setBackgroundResource(R.drawable.EXAMPLE_OF_A_BACKGROUND)
it.isClickable = true
it.isFocusable = true
// I want this view to be clickable and provide material feedback...
val foregroundResId = context.theme.getThemeAttributeValue(R.attr.selectableItemBackground, false)
it.foreground = context.theme.getDrawable(foregroundResId)
}
context.theme.obtainStyledAttributes(attrs, R.styleable.MyCustomView, defStyle, 0).run {
initProperties(this)
recycle()
}
}
private fun initProperties(typedArray: TypedArray) = with(typedArray) {
// The names of these attrs are a mix from attr.xml + the attr name.
getString(R.styleable.MyCustomView_title).also { setTitle(it) }
getDrawable(R.styleable.MyCustomView_android_drawable).also { setImage(it) }
}
private fun setTitle(title: CharSequence?) {
title.text = title
}
private fun setImage(source: Drawable?) {
source?.let {
image.setImageDrawable(it)
}
}
}
This is all supported by my layout: R.layout.HERE_GOES_THE_LAYOUT
Here's a simplified version:
<?xml version="1.0" encoding="utf-8"?>
<merge 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"
tools:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<ImageView
android:id="@+id/image"
android:layout_width="40dp"
android:layout_height="40dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/title"
app:layout_constraintBottom_toBottomOf="parent" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="@id/image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:gravity="center_vertical" />
</merge>
And how do I use this?
In any layout! E.g.:
<Some ViewGroup like LinearLayout It Doesn't Matter .... >
<com.the.package.of.your.MyCustomView
android:id="@+id/yourCustomViewOne"
android:layout_width="match_parent"
android:layout_height="wrap_content"
<!-- HERE ARE THE TWO 'custom' ATTRIBUTES -->
android:drawable="@drawable/some_drawable_of_your_choice"
app:title="@string/some_string" />
<com.the.package.of.your.MyCustomView
android:id="@+id/yourCustomViewTwo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawable="@drawable/a_different_drawable_perhaps"
app:title="@string/and_also_a_different_string />
</Some ViewGroup like LinearLayout It Doesn't Matter>
Hopefully you get the idea. You can add more custom attributes, or even (like I did) use an Android one, and internally give it your own meaning (overriding an android attribute and misusing it would likely confuse your users, so be "smart"). E.g.: if the above custom view had MORE than one image, using android:Drawable
may not be a great choice, because users wouldn't be sure what drawable is that thing setting... in this example it works "fine" because you only have one image.
Last but not least, don't neglect Accessibility! Provide descriptions where you see fit, test with TalkBack, etc.
How does this answer the question?
Well, you don't need to "expand" the custom view, you just need to encapsulate the dynamic properties so whoever is using the Widget/View, can provide the values via XML (or programmatically) and your custom view does the job behind the scenes.
Related Topics
Change Background of Edittext's Error Message
Not Seeing Nexus7 in Eclipse's Android Devices
Android Wsdl/Soap Service Client
Android Edittext Listener for Cursor Position Change
What Would Happen If Android App Is Released with Debuggable On
Bitmapfactory.Decodestream Out of Memory Despite Using Reduced Sample Size
Creating a Seterror() for The Spinner
How to Access Resource with Dynamic Name in My Case
How to Check Database on Not Rooted Android Device
Notification Passes Old Intent Extras
Change Edittext Password Mask Character to Asterisk (*)
How to Specify Location of Debug Keystore for Android Ant Debug Builds
How to Set Android Tablayout in The Bottom of The Screen
End Incoming Call Programmatically
How to Hide "Navigation" and "Gps Pointer" Buttons When I Click The Marker on The Android Google Map