7

in application i can simply define attr.xml into values and use that into design layout. but i can not set this attributes programical into widgets, for example i have this attribute:

<declare-styleable name="ButtonTextStyle">
    <attr name="font_button">
        <enum name="consolas"      value="0" />
        <enum name="times"    value="1" />
    </attr>
</declare-styleable>

and i can use this attribute into xml by:

<com.sample.app.Widgets.ButtonTextStyle
    android:id="@+id/btn_way_bill_click"
    android:layout_width="fill_parent"
    app:font_button="consolas">

now i'm define some Button programical into project and i want to use consolas font defined into font_button by:

button.setTextAppearance(context, R.attr.font_button);

but i get error for this code and i can not resolve problem, i'm define custom class extends from Button like with this:

public class ButtonTextStyle extends Button {
    private Context mContext;
    public ButtonTextStyle(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mContext = context;
        init(attrs, defStyle);
    }

    public ButtonTextStyle(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        init(attrs,-1);
    }

    public ButtonTextStyle(Context context) {
        super(context);
        mContext = context;
        init(null,-1);
    }

    private void init(AttributeSet attrs,int defStyle) {
        if (!isInEditMode()) {
            TypedArray a = mContext.obtainStyledAttributes(attrs,R.styleable.ButtonTextStyle, defStyle, 0);
            String str = a.getString(R.styleable.ButtonTextStyle_font_button);
            switch (Integer.parseInt(str)) {
                case 0:
                    str = "fonts/consolas.ttf";
                    break;
                case 1:
                    str = "fonts/times.ttf";
                    break;
            }
            setTypeface(FontManager.getInstance(getContext()).loadFont(str));
        }
    }
}

PROBLEM:

Expected resource of type style

and i can not set for example enum to widgets like with set times font

HOW to set programical this custom class with attribute defined into attr.xml

UPDATED: my class to add button is below method. i want to set font for it programically:

private void addButton(final CDialog owner, final Dialog dialog, final DialogButton dlgBtn) {
    LinearLayout linearLayout = (LinearLayout) dialog.findViewById(R.id.tsw__layerButton);
    LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 70);
    //layoutParams.setMargins(11, 0, 8, 0);

    Button button = new Button(context);
    if (buttonTheme != -1) {
        button.setBackgroundResource(buttonTheme);
    }
    button.setPadding(0,2,0,0);
    button.setGravity(Gravity.CENTER);
    button.setText(buttonMsg[dlgBtn.ordinal()]);
    button.setTextSize(14);
    button.setTextColor(G.context.getResources().getColor(R.color.white_text));
    button.setWidth(dpToPx(buttonWidth));
    //button.setHeight(dpToPx(32));
    button.setLayoutParams(layoutParams);

    button.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            dialog.dismiss();
            if (dialogListener != null) {
                dialogListener.onCloseDialog(owner, dlgBtn);
            }
        }
    });
    linearLayout.addView(button);
}

2 Answers2

3

Maybe this article will help you Android: Set Custom Attributes Programmatically and Via XML. Note, that there should be a style assigned to the R.attr.font_button attribute somewhere (for example in "AppTheme"). Because it's just an attribute, and it holds a reference to a value.

If you assigned a style in "AppTheme":

ButtonTextStyle button = (TextView) findViewById(R.id.btn_way_bill_click);
Resources.Theme themes = getTheme();
TypedValue storedValueInTheme = new TypedValue();
if (themes.resolveAttribute(R.attr.font_button, storedValueInTheme, true))
    button.setTextAppearance(storedValueInTheme.data);

Or if you declared your own theme. It can be declared as follows

<resources>
    <style name="ConsolasBtn" parent="@android:style/Widget">
        <item name="font_button">consolas</item>
    </style>
</resources>

Then you need to apply this theme to your button. Try

ButtonTextStyle button = (TextView) findViewById(R.id.btn_way_bill_click);
button.setTextAppearance(this, R.style.ConsolasBtn);  // *this* refers to Context

Or try to pass R.style.ConsolasBtn to your constructor ButtonTextStyle(Context context, AttributeSet attrs, int defStyle) as the defStyle argument.

See also Styles and Themes, Resources.Theme, TypedValue, attrs.

Community
  • 1
  • 1
naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
2

I believe the proper way to achieve what you are trying to do is by first declaring an enum attribute...

<declare-styleable name="ButtonTextStyle">
    <attr name="font_button" format="enum"> 
        <enum name="consolas"      value="0" />
        <enum name="times"    value="1" />
    </attr>
</declare-styleable>

Only change from your original code is the format attribute. Then you can declare those custom style attributes as below...

<com.sample.app.Widgets.ButtonTextStyle
    android:id="@+id/btn_way_bill_click"
    android:layout_width="fill_parent"
    app:font_button="consolas">

but, don't forget to declare the namespace(s) your sub-widget belongs to in the parent layout, otherwise you won't be able to reference the app alias

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res/com.sample.app.Widgets">

and finally, your init method would look something like this...

private void init(AttributeSet attrs,int defStyle) {
        if (!isInEditMode()) {
            int i = -1;
            TypedArray a = mContext.obtainStyledAttributes(attrs,R.styleable.ButtonTextStyle, defStyle, 0);

            try{
                a.getInt(R.styleable.ButtonTextStyle_font_button, -1);
            }
            finally{
               a.recycle();
            }

            switch (i) {
                case 0:
                    str = "fonts/consolas.ttf";
                    break;
                case 1:
                    str = "fonts/times.ttf";
                    break;
            }

            setTypeface(FontManager.getInstance(getContext()).loadFont(str));
        }
    }

Setting the property programmatically

To set that property programmatically, you will need to expose a "setter" method that takes an integer value, then based on that value you can change the type face. To make things easier for consumers of your custom widget you can also define two constants in your class...

public static final int CONSOLAS = 0;
public static final int TIMES = 1;

then define the setter method...

  public void setFontButton(int fontButton) {
        if (fontButton != CONSOLAS && fontButton != TIMES) {
            throw new IllegalArgumentException(
                    "fontButton must be one of CONSOLAS or TIMES");
        }

        //load the font and set it here, the same way you did in "init"
    }

All you have to do is call that setter method and pass in one of the constants specified...

buttonTextStyle1.setFontButton(ButtonTextStyle.CONSOLAS);

Yet ANOTHER Update

Instead of doing...

  Button button = new Button(context);

do...

 ButtonTextStyle button = new ButtonTextStyle(context);

and make sure you import the correct class so it can be used in code...

 import com.sample.app.Widgets.ButtonTextStyle;
Leo
  • 14,625
  • 2
  • 37
  • 55
  • i say i dont have any problem to set attribute via xml, my problem is set that programical –  Apr 17 '15 at 07:46
  • thanks sir. i want to set `app:font_button="consolas"` like with xml via programical :) –  Apr 17 '15 at 08:01
  • thanks sir, i can use this method. my widgets is Button and i'm define that by this way: `Button button = new Button(context);` and i dont know whats `buttonTextStyle1` and my app could not detect `ButtonTextStyle.CONSOLAS` –  Apr 17 '15 at 08:38
  • Your widget is `ButtonTextStyle`...unless I'm missing something. If you cast `button` to `ButtonTextStyle` you should have no problems...I'm pretty sure you know what I'm saying otherwise you wouldn't be able to write all that code in first place – Leo Apr 17 '15 at 08:48
  • hope this help, mate. If you happen to have more doubts. Please post a different question!!!! – Leo Apr 17 '15 at 09:04