I create an attribute in attrs.xml file:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Custom">
<attr name="src" format="integer" />
</declare-styleable>
</resource>
And in my code, I get the value of the attribute like this:
attrs.getAttributeIntValue("mynamespace", "src", -1);
It works. I get the value of 'src' from the layout xml file.
But my question is why android does not generate a value in R class so that I don't need to use the string 'src' again in my java code?
Instead use the TypedArray
public CustomView(final Context context) {
this(context, null);
}
public CustomView(final Context context,
final AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(final Context context,
final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.Custom, defStyle, 0);
int src = a.getInt(R.styleable.Custom_src, 0);
a.recycle();
}
Related
I have declared some custom attributes for my custom view
<declare-styleable name="MenuItemView">
<attr name="item_icon" format="reference" />
<attr name="item_title_color" format="reference" />
</declare-styleable>
When I create the view, I obtain the styled attributes. I have tried both context.obtainStyledAttributes and context.getTheme().obtainStyledAttributes
public MenuItemView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context, context.obtainStyledAttributes(
attrs,
R.styleable.MenuItemView,
0, 0));
}
public MenuItemView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, context.obtainStyledAttributes(
attrs,
R.styleable.MenuItemView,
defStyleAttr, 0));
}
And then I try to get the drawable
public void initView(Context context, TypedArray a) {
inflate(context, R.layout.menu_item, this);
this.title = findViewById(R.id.tvTitle);
this.icon = findViewById(R.id.ivIcon);
try {
title.setTextColor(a.getColor(R.styleable.MenuItemView_item_title_color, getResources().getColor(R.color.midnight_black)));
Drawable iconDrawable = a.getDrawable(context, R.styleable.MenuItemView_item_icon);
...
} finally {
a.recycle();
}
}
On my phone, everything works fine, but on Android 4, it just says
Caused by: android.content.res.Resources$NotFoundException: File res/drawable/ic_profile_circle.xml from drawable resource ID #0x7f08012b
I found a very hacky way around this issue by switching the attribute type from a reference to a string and then doing this bit of nastiness
String indentifier = a.getString(R.styleable.MenuItemView_item_icon);
indentifier = indentifier.replace(".xml", "").replace("res/drawable/", "");
int id = context.getResources().getIdentifier(indentifier, "drawable", context.getPackageName());
Drawable iconDrawable = ContextCompat.getDrawable(context, id);
It's just enough to get color and icon and set for your views!
int titleColorId = a.getResourceId(R.styleable.MenuItemView_item_title_color, getResources().getColor(R.color.midnight_black));
int iconId = a.getResourceId(R.styleable.MenuItemView_item_icon, -1);
title.setTextColor(titleColorId);
if (iconId != -1)
icon.setImageResource(iconId);
I got the error when use attribute in child view of a CustomLayout (I have define a custom LayoutParams to allow child view use this attribute)
However, code's still RUNNING and display correct value (you can check my code below, when I run app it will display "Hello" in logcat)
Here is my code
style.xml
<declare-styleable name="CustomRelativeLayout_Layout">
<attr name="title" format="string" />
</declare-styleable>
CustomRelativeLayout class
public class CustomRelativeLayout extends RelativeLayout {
public CustomRelativeLayout(Context context) {
this(context, null);
}
public CustomRelativeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new CustomLayoutParams(getContext(), attrs);
}
#Override
public void onViewAdded(View child) {
super.onViewAdded(child);
CustomLayoutParams layoutParams = (CustomLayoutParams) child.getLayoutParams();
Log.i("TAG", "title = " + layoutParams.title);
}
final class CustomLayoutParams extends RelativeLayout.LayoutParams {
String title;
CustomLayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray ta =
c.obtainStyledAttributes(attrs, R.styleable.CustomRelativeLayout_Layout);
title = ta.getString(R.styleable.CustomRelativeLayout_Layout_title);
ta.recycle();
}
}
}
Of course, I can disable it by add tools:ignore="MissingPrefix" but I don't like this much. Any help or suggestion would be great appreciated.
Here is my demo https://github.com/PhanVanLinh/AndroidPassAttributeToChildVIew
After many try, I found a solution for my problem
Change title to layout_title will make the error gone
<declare-styleable name="CustomRelativeLayout_Layout">
<attr name="title" format="string" />
</declare-styleable>
The magic is layout_ because the error still happened if I use like
title_, title_dasdasdsad, lo_title, title_23232
I tried with THIS LINK to change the typeface of all preferences of PreferenceScreen.
It was changed everywhere except summary of ListPreference.
Can anyone has an idea how to apply custom font on summary of ListPreference?
UPDATE
I want to apply my custom font exist on assets folder, not the in-build one. Also android:textAppearanceListItemSecondary required API 21, my app support minimum API 15.
Finally the way to change the font for summary of ListPreference.
Override the onBindViewHolder method of ListPreference to set your custom typeface. Check below custom class.
public class CustomListPreference extends ListPreference {
private String typefaceTitle, typefaceSummary;
public CustomListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
public CustomListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
public CustomListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public CustomListPreference(Context context) {
super(context);
}
#Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
if(!TextUtils.isEmpty(typefaceTitle)) {
TextView titleView = (TextView) holder.findViewById(android.R.id.title);
titleView.setTypeface(FontManager.getInstance().getFont(typefaceTitle));
}
if(!TextUtils.isEmpty(typefaceSummary)){
final TextView summaryView = (TextView) holder.findViewById(
android.R.id.summary);
summaryView.setTypeface(FontManager.getInstance().getFont(typefaceSummary));
}
}
private void init(Context context, AttributeSet attrs){
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.Preference);
typefaceTitle = a.getString(R.styleable.Preference_typefaceTitle);
typefaceSummary = a.getString(R.styleable.Preference_typefaceSummary);
a.recycle();
}}
attrs.xml
<declare-styleable name="Preference">
<attr name="typefaceTitle" format="string"></attr>
<attr name="typefaceSummary" format="string"></attr>
</declare-styleable>
Usage in Preference screen.
<YOUR_CustomListPreference_PACKAGE_NAME.CustomListPreference
android:defaultValue="X"
android:dialogTitle="Dialog Title"
android:entries="#array/list_item_title"
android:entryValues="#array/list_item_value"
android:key="pref_list"
android:summary="%s"
android:title="#string/Preference Title"
app:typefaceTitle="YOUR FONT NAME"
app:typefaceSummary="YOUR FONT NAME"/>
Hope this help for other.
try this
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="android:textAppearanceListItemSecondary">#style/textAppearanceListItemSecondaryCustom</item>
</style>
<style name="textAppearanceListItemSecondaryCustom">
<item name="android:textSize">14sp</item>
<item name="android:typeface">monospace</item>
</style>
i'm created simple widget extends from ImageView, in this simle code i want to set image into ImageView from layout xml,i want change background imageview image and change image to set other image into ImageView, but my problem in first time dont show image
1) i'm create new attribute into attr.xml:
<declare-styleable name="CIconButton">
<attr name="button_icon" format="integer" />
<attr name="background_icon" format="reference" />
</declare-styleable>
2) use CIconButton class into layout:
<!-- xmlns:app="http://schemas.android.com/apk/res/com.sample.app.tpro" -->
<com.sample.widget.CIconButton
android:id="#+id/imgv_update_selected_phones"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
app:button_icon="#drawable/icon_add_action" />
3) CIconButton class
public class CIconButton extends ImageView implements OnClickListener {
private Drawable mSelectedBackground;
public CIconButton(Context context) {
super(context, null);
}
public CIconButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CIconButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CIconButton, defStyle, 0);
mSelectedBackground = a.getDrawable(R.styleable.CIconButton_button_icon);
setImageDrawable(mSelectedBackground);
a.recycle();
setOnClickListener(this);
}
#Override
public void onClick(View v) {
}
}
PROBLEM:
my custom widgets class dont show image set into layout xml, for example this class dont show icon_add_action from drawable
My problem resolved , i must be change second constructor as :
public CIconButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
to:
public CIconButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
this call last this class constrctor
I'm using some simvot number picker in application, I want to create custom widget for that and use in all of project, now i'm create this files but I can not set any value for custom widget.
My attributes:
<declare-styleable name="CNumberPicker">
<attr name="maxValue" format="string" />
<attr name="minValue" format="string" />
<attr name="value" format="string" />
</declare-styleable>
My Custom NumberPicker widget:
public class CNumberPicker extends net.simonvt.numberpicker.NumberPicker implements OnClickListener {
private int maxValue;
private int minValue;
private int value;
public CNumberPicker(Context context) {
super(context);
}
public CNumberPicker(Context context, AttributeSet attrs) {
super(context, attrs);
processAttributeSet(attrs);
}
public CNumberPicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CNumberPicker, defStyle, 0);
processAttributeSet(attrs);
maxValue = Integer.parseInt(a.getString(R.styleable.CNumberPicker_maxValue));
minValue = Integer.parseInt(a.getString(R.styleable.CNumberPicker_minValue));
a.recycle();
setOnClickListener(this);
}
#Override
public void onClick(View v) {
}
private void processAttributeSet(AttributeSet attrs) {
this.setMaxValue(attrs.getAttributeIntValue(null, "maxValue", 0));
}
}
My defined widget into xml:
<com.sample.widget.CNumberPicker
android:id="#+id/np_choose_hour"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:layout_weight="0.20"
android:gravity="center_horizontal"
app:maxValue="10"
app:minValue="1"
app:value="5">
</com.sample.widget.CNumberPicker>
how to set value defined into xml in layout?
You have to inflate the layout in code.
public CNumberPicker(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.cnumberpicker, this);
}
presuming the layout file is cnumberpicker.xml
EDIT: These 3 functions are constructors. Any one of them could be called to construct the object. By using this instead of super we can force all constructors to end up calling the 3 parameter constructor. You need some cohesion here. You don't want to copy paste code every time you make one change.
public CNumberPicker(Context context) {
this(context, null);
}
public CNumberPicker(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CNumberPicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CNumberPicker, defStyle, 0);
processAttributeSet(attrs);
// this method allows a default value if no attributes are given. You should use them.
maxValue = Integer.parseInt(a.getString(R.styleable.CNumberPicker_maxValue,"10"));
minValue = Integer.parseInt(a.getString(R.styleable.CNumberPicker_minValue,"0"));
a.recycle();
}