Is there any way to change the font for an entire Android application ? I'm aware of changing the font for each TextView and Buttons. I just wanted to know if there's a more elegant way of doing it since the program i'm working on has tons of layout files :(
to Apply same font effect through out the app you need to create your own custom TextView and Button class which has applied your custom font. and the use them in your layouts as normal views.
public class MinnesotaTextView extends TextView{
public MinnesotaTextView(Context context) {
super(context);
if(!isInEditMode()){
textViewProprties(context);
}
}
public MinnesotaTextView(Context context, AttributeSet attrs){
super(context, attrs);
if(!isInEditMode()){
textViewProprties(context);
}
}
public MinnesotaTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if(!isInEditMode()){
textViewProprties(context);
}
}
private void textViewProprties(Context context){
Typeface tfs = Typeface.createFromAsset(context.getAssets(), "Helvetica.ttf");
setTypeface(tfs);
setMaxLines(4);
}
}
here's Button:
public class MinnesotaButton extends Button {
public MinnesotaButton(Context context){
super(context);
if(!isInEditMode()){
buttonProprties(context);
}
}
public MinnesotaButton(Context context, AttributeSet attrs){
super(context, attrs);
if(!isInEditMode()){
buttonProprties(context);
}
}
public MinnesotaButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if(!isInEditMode()){
buttonProprties(context);
}
}
private void buttonProprties(Context context){
setPadding(0, 4, 0, 0);
setBackgroundResource(R.drawable.bg_red_btn);
setGravity(Gravity.CENTER_HORIZONTAL|Gravity.CENTER_VERTICAL);
setTextSize(13.0f);
setTextColor(context.getResources().getColor(R.color.white));
Typeface tfs = Typeface.createFromAsset(context.getAssets(), "garreg.ttf");
setTypeface(tfs,1);
}
}
There are two ways you can do this, depending on how much control you need:
1) You can create a custom style attribute in styles.xml, something like:
<style name="CodeFont" parent="#android:style/TextAppearance.Medium">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">#00FF00</item>
<item name="android:typeface">monospace</item>
</style>
Keep in mind that this is a pretty limited approach, style may not contain everything you need.
2) You can create subclasses of TextView and Button and put your styling code in their constructors. I'd recommend this way because you can use whatever custom assets you might need. (I just saw that Nasser beat me to a code sample for this, check it out - it looks right)
You can play with several attributes related to your theme to modify the default font colors on your application.
Here is an example for the theme Holo Light, you have to first change your manifest file to call your custom theme, and then customize your custom theme in the file styles.xml.
Here is the part of the manifest file you need to change to call your custom theme (the custom theme called here is AppTheme:
<application
android:name="YourApplication"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
Then in your file styles.xml, create and customize this custom theme:
<style name="AppTheme" parent="#android:style/Theme.Holo.Light">
<item name="android:textColorPrimary">#color/red</item>
<item name="android:textColorSecondary">#color/blue</item>
<item name="android:textColorTertiary">#color/yellow</item>
</style>
These 3 parameters textColorPrimary, textColorSecondary and textColorTertiary will impact elements/components all over your application.
Related
I made a library with a custom view that inflates a layout when created. Views in the layout are styled with style="?attr/labelStyle" or any other attribute.
The attribute is declared the library's attrs.xml:
<attr name="myViewStyle" format="reference"/>
<declare-styleable name="MyView">
<attr name="labelStyle" format="reference|color"/>
</declare-styleable>
I have set a default value to this attribute in the library's styles.xml:
<style name="MyViewStyle">
<item name="labelStyle">#style/LabelStyle</item>
</style>
<style name="LabelStyle">
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="...">...</item>
</style>
And finally in the library's themes.xml:
<style name="MyViewStyleLight" parent="Theme.AppCompat.Light">
<item name="myViewStyle">#style/MyViewStyle</item>
</style>
Now this was the library's default styles, but it is overridden in the main project styles.xml
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="myViewStyle">#style/MyViewStyleCustom</item>
</style>
<style name="MyViewStyleCustom" parent="MyViewStyleLight">
<item name="android:textColor">#color/gray</item>
<item name="...">...</item>
</style>
The custom view code:
public MyView(Context context) {
this(context, null, R.attr.myViewStyle, 0);
}
public MyView(Context context, #Nullable AttributeSet attrs) {
this(context, attrs, R.attr.myViewStyle, 0);
}
public MyView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(createThemeWrapper(context, R.attr.myViewStyle, R.style.MyViewStyleLight),
attrs, defStyleAttr, defStyleRes);
initLayout();
}
private static Context createThemeWrapper(Context context, int styleAttr, int defaultStyle) {
final TypedArray ta = context.obtainStyledAttributes(new int[]{styleAttr});
int style = ta.getResourceId(0, defaultStyle);
ta.recycle();
return new ContextThemeWrapper(context, style);
}
private void initLayout() {
LayoutInflater inflater = LayoutInflater.from(getContext());
inflater.inflate(R.layout.my_view, this);
...
}
I explain about the ContextThemeWrapper below. Now the app crashes on the line where the layout gets inflated. Here's the important part of the crash log:
android.view.InflateException: Binary XML file line #0: Binary XML file line #0: Error inflating class com.example.MyView
at android.view.LayoutInflater.inflate(LayoutInflater.java:539)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
[...]
Caused by: java.lang.UnsupportedOperationException: Failed to resolve attribute at index 13: TypedValue{t=0x2/d=0x7f030057 a=-1}
at android.content.res.TypedArray.getDrawable(TypedArray.java:867)
[...]
The layout inflater can't find the attribute's value. When I tried to get the attribute by code, it returns nothing. The attribute actually exists, only it has no value set to it even though I have clearly set one.
How exactly I am supposed to style my library? I am almost certain that I did every thing the same as the SublimePicker library but it just won't work. There's a little difference in the part with the ContextThemeWrapper, but it probably isn't the problem. I feel like I forgot a tiny thing somewhere that makes the attribute have no value, something is not connected, I don't know.
I know this is a very long question, but it cannot be more concise, I simplified everything as much as I could. I changed most of the information that was in the previous version of my question, making it completely different. The two answers are not relevant at all now, not that they ever were. The bounty was automatically rewarded.
If that could help someone I can add a download to my actual project, but as I said this simplified example has the exact same form as my project.
This answer is based on what I understand from your question and conversation between you and Vinayak B. If I misinterpret ,Please correct me.
there is difference in style.xml in both place app as well as lib. addition I have removed theme.xml as well as changes in constructor of MyView.java for default style
I have changed following things
overridden in the main project styles.xml
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="myViewStyle">#style/MyViewStyleCustom</item>
</style>
<style name="MyViewStyleCustom" parent="MyViewStyle">
<item name="labelStyle">#style/LabelStyle123</item>
</style>
<style name="LabelStyle123">
<item name="android:textColor">#f00</item>
</style>
lib styles.xml
<resources>
<style name="MyViewStyle">
<item name="labelStyle">#style/LabelStyle</item>
<item name="TextStyle">#style/textStyle</item>
</style>
<style name="LabelStyle">
<item name="android:textColor">#00f</item>
</style>
<style name="textStyle">
<item name="android:textColor">#009</item>
</style>
</resources>
MyView.java - changed constructor of and set default MyViewStyle if no any attribute come from application.
public MyView(Context context) {
this(context, null, R.attr.myViewStyle, R.style.MyViewStyle);
}
public MyView(Context context, #Nullable AttributeSet attrs) {
this(context, attrs, R.attr.myViewStyle, R.style.MyViewStyle);
}
public MyView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, R.style.MyViewStyle);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(createThemeWrapper(context, defStyleAttr,defStyleRes), attrs, defStyleAttr, defStyleRes);
initLayout();
}
private static Context createThemeWrapper(Context context, int styleAttr, int defaultStyle) {
final TypedArray ta = context.obtainStyledAttributes(new int[]{styleAttr});
int style1 = ta.getResourceId(0, defaultStyle);
ta.recycle();
return new ContextThemeWrapper(context, style1);
}
so either it will take default labelStyle if it is not overridden in main activity style or overridden labelStyle
This answer is based on what I understand from your question. If I misinterpret
,Please correct me.
First of all myTextColor is an attribute name in your library. not a attribute value. You supposed to give a value for myTextColor when ever you using this library. Otherwise there may occur 'InflateException' . You can avoid this by following way.
<YourCustomeView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:myTextColor="#000"/>
1. Set myTextColor value directly when you use outside the library.
OR
In your library where you using this myTextColor attribute, check if this attribute have value or not. If it doesn't have any value then use a default value for myTextColor
private void init(#Nullable AttributeSet attrs) {
TypedArray ta = getContext().obtainStyledAttributes(attrs,
R.styleable.MyLibrary);
boolean hasRawRes = ta.hasValue(R.styleable.myTextColor);
if(hasRawRes){
// Use `myTextColor` attr here
}else{
// use default color
}
}
UPDATE ANSWER
This answer for the updated question
First of all you are trying to fetch a attr value from your library to your project using ?attr/ .Which does not going to work. because
Your project using Theme.AppCompat theme as (I'm guessing) parent theme for your Activities. When you use ?attr inside that activity, you can only fetch attribute values of Theme.AppCompat. But you are trying to fetch ?attr/labelStyle which is not a attribute of Theme.AppCompat rather than it's your library attribute. That's why you are getting that crash. If you want to use any style from your library to your project you can use #style tag
For example
style="#style/labelStyle"
If it's not what you are looking for ,Please kindly share your source code.So I can understand more on this problem.
Here's my guess: I suspect that, despite <style> tag you posted above, the attribute is actually not defined when inflating from your library, probably because your library project is using a Context with a "bad" theme when inflating the dialog.
The ?attr syntax means that the value for the variable is read from the context's theme, not from a view's style or attributes. From a Google dev blog post:
This ?attr/ format allows you to pull any attribute out of your theme, making it easy to consolidate your theming into a single place and avoid finding/replacing across many files.
So you have to make sure that you either handle the case where the inflating context's theme does not define this attribute, or only ever inflate this dialog with a theme that defines the attribute.
I have a custom font file, say myfont.ttf in assets/fonts/
I have created a custom View like this
public class IconFontView extends AppCompatTextView {
public IconFontView(Context context) {
super(context);
applyIconFonts(context);
}
public IconFontView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
applyIconFonts(context);
}
public IconFontView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
applyIconFonts(context);
}
private void applyIconFonts(final Context context) {
final Typeface iconFont = Typeface.createFromAsset(context.getAssets(), "fonts/myfont.ttf");
setTypeface(iconFont);
}
}
in XML:
<com.smule.singandroid.customviews.IconFontView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="400dp"
android:text="#string/icontext"/> <!-- my unicode for the specific icon -->
strings.xml:
<string name="icontext"></string>
This way, I can see the preview perfectly fine.
But, if I enter this fragment, I see nothing but an empty view. (using "Show layout bounds" to tell you that this view exists there, just not drawing)
HOWEVER, if I add this font to my styles.xml like this
<style name="IconFont">
<item name="fontPath">fonts/myfont.ttf</item>
</style>
and apply it in layout xml like this
<com.smule.singandroid.customviews.IconFontView
style="#style/IconFont"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="400dp"
android:text="#string/icontext"/> <!-- my unicode for the specific icon -->
This not only displays correct preview, but also shows the icon perfectly fine.
This has same effect as doing something like
mIconFontview.setText(R.string.icontext);
mIconFontView.setTypeFace(...);
Why would this work this way?
Then there would be no reason to create IconFontView at all. Might as well just use TextView.
So there are different ways to set your font in Android.
What i need to do is to set the font in combination with a custom font and thereby over the entire app.
Now after some research i have 2 options.
Override EditText and set font, use this class in my layout xml.
Add a font to my AppTheme in my styles.xml.
Now i prefer the last option, this is obviously in my position the best way to go since i use the same font in my entire app.
Now the problem is, in my Assets/font/ folder i added the font i want to use but i can't use this in my styles.
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:typeface"> Here? </item>
</style>
How to add my font as typeface. Is that possible?
Try this code:
public class CustomTextView extends EditText {
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (!isInEditMode())
init();
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
if (!isInEditMode())
init();
}
public CustomTextView(Context context) {
super(context);
if (!isInEditMode())
init();
}
public void init() {
Typeface tf = Typeface.createFromAsset(getContext().getAssets(), Constants.FONTPATH);
setTypeface(tf);
}
}
Then Use in XMLwith ;
<pkgname.CustomTextView android:id="#+id/txt" android:layout_width="wrap_content" android:layout_height="wrap_content" />
As far as I know there is no way we can access external assets in xml files.
I want to theme the ShareActionProvider of the ActionBarSherlock. My problem is that I successfully customized the styles of the ActionBar but I cannot style the share popup which comes from the ActionBarSherlock.
In the Screenshot above you can see the share popup uses the default styles while a normal more popup is styled in that way I like.
I digged more thrue the source code and found in ActivityChooserView this method:
private IcsListPopupWindow getListPopupWindow() {
if (mListPopupWindow == null) {
mListPopupWindow = new IcsListPopupWindow(getContext());
//...
Which is as far I know responsable for creating that Popup of the ShareActionProvider. As you can see above a new instance of IcsListPopupWindow is created. Here are the constructors of IcsListPopupWindow:
public IcsListPopupWindow(Context context) {
this(context, null, R.attr.listPopupWindowStyle);
}
public IcsListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
mContext = context;
mPopup = new PopupWindow(context, attrs, defStyleAttr);
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
}
So far the attr com.actionbarsherlock.R.attr.listPopupWindowStyle used. While this attr is inserted the one and two parameter constructor of IcsListPopupWindow created a new PopupWindow with the attr com.android.internal.R.attr.popupWindowStyle which seems to be equal with android.R.attr.popupWindowStyle:
public PopupWindow(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.popupWindowStyle);
}
public PopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
mContext = context;
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
TypedArray a =
context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.PopupWindow, defStyleAttr, defStyleRes);
mBackground = a.getDrawable(R.styleable.PopupWindow_popupBackground);
// ...
There you can see that the background image is loaded from a style called styleable.PopupWindow_popupBackground. I tried to apply my style with this xml file:
<style name="Theme.MyStyle" parent="#style/Theme.Sherlock.Light.DarkActionBar">
<!-- ... -->
<item name="actionDropDownStyle">#style/DropDownNav.MyStyle</item>
<item name="dropDownListViewStyle">#style/DropDownListView.MyStyle</item>
<item name="actionBarItemBackground">#drawable/selectable_background_mystyle</item>
<item name="listPopupWindowStyle">#style/DropDownNav.MyStyle</item>
<item name="android:listPopupWindowStyle">#style/DropDownNav.MyStyle</item>
</style>
<style name="DropDownNav.MyStyle" parent="#style/Widget.Sherlock.Spinner.DropDown.ActionBar">
<item name="android:popupBackground">#drawable/menu_dropdown_panel_mystyle</item>
<item name="android:divider">#081925</item>
<item name="android:dividerHeight">1dp</item>
</style>
<style name="DropDownListView.MyStyle" parent="#style/Widget.Sherlock.ListView.DropDown">
<item name="android:divider">#081925</item>
<item name="android:dividerHeight">1dp</item>
</style>
But it does not work. What am I doing wrong?
By the way I would be really happy if someone could give me a good tutorial for styleable and the attr stuff I don't get it right.
I was able to override the popupBackground color by overriding this ABS style:
<style name="Widget.Sherlock.Light.ListPopupWindow" parent="Widget">
<item name="android:popupBackground">#333333</item>
</style>
Hopefully that can get you going. And if you were able to solve it on your own, please share with the rest of us how you styled the rest of the attributes.
Cheers
The CheckBox class extends the CompoundButton, but add nothing to it. But some how it obtains it's respective look. I found some declarations in Android sources, but wonder how they are mapped to CheckBox class?
public class CheckBox extends CompoundButton {
public CheckBox(Context context) {
this(context, null);
}
public CheckBox(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.checkboxStyle);
}
public CheckBox(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
}
Styles
<style name="Theme">
<item name="checkboxStyle">#android:style/Widget.CompoundButton.CheckBox</item>
</style>
<style name="Widget.CompoundButton.CheckBox">
<item name="android:background">#android:drawable/btn_check_label_background</item>
<item name="android:button">#android:drawable/btn_check</item>
</style>
EDIT:
Probably I was not clear... I understand how the drawable assigned to Widget.CompoundButton.CheckBox style, but how this style assigned to CheckBox class? I see the ".CheckBox" in the style name, but is this naming convention really what makes the trick? If so, what are the rules? If I derive MyCheckBox from CompoundButton, can I just define the Widget.CompoundButton.MyCheckBox style and it will work?
There's your answer: <item name="android:button">#android:drawable/btn_check</item>
A drawable can have multiple states (whether or not the element is focused, pressed, etc), and that's where the different states of the checkbox are.
EDIT: After you revised your question, I see that you're looking for something different. Again, it's all in what you posted:
<style name="Widget.CompoundButton.CheckBox">
This is the style.
<item name="checkboxStyle">#android:style/Widget.CompoundButton.CheckBox</item>
The main theme (android.internal.R.attr) has an attribute "checkboxStyle" that points to this style.
public CheckBox(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.checkboxStyle);
}
The constructor assigns that attribute to the view. And that's it.
Right here
<item name="android:button">#android:drawable/btn_check</item>