How to read android default attributes of a View in java code - java

I want to have a custom TextView called MyTextView and i want to set a default TextSize in it's constructor only if no TextSize has been set in it's XML definition. How can i detect if a TextSize has been set in it's XML definition?
public class MyTextView extends TextView{
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
//How can i read TextSize from AttribureSet??
//if no TextSize has been set then SetTextSize(defaultTextSize);
}
}
Can any one help me please?

You can obtain style attributes like
public class MyTextView extends TextView{
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
String size = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "textSize");
}
}

Here's example:
final Resources.Theme theme = context.getTheme();
TypedArray array = theme.obtainStyledAttributes(attrs, R.styleable.YourStylable, R.attr.YourDefStyleAttr, 0);

Try this float size = new TextView(this).getTextSize();

Related

Loading custom fonts without using a context

I already know Java and how it works, but I am new with the android related stuff. I have a font I want to use, and I want to load it in a separate class, however all the sites I found that show an example require the context from the MainActivity object, because it uses the getAssets() function. I need to load the font in without using that function.
Example of what I was shown
// This works, but I don't have access to the getContext().getAssets()
// in my separate class. Is there anyway I can do this without this function or XML?
Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "fonts/ExampleFont.ttf");
create CustomTextView class and use it your xml directly as Regular textview like below
customtextview class file
public class CustomTextView extends TextView {
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomTextView(Context context) {
super(context);
init();
}
private void init() {
Typeface tf = Typeface.createFromAsset(getContext().getAssets(),
"fonts/opensans.ttf");
setTypeface(tf);
}
}
use this as
<core.com.example.CustomTextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#color/colorBlack"
android:textSize="14sp"
android:text="Test text with custom font"
android:lineSpacingExtra="2dp"
/>
UPDATE
As #EugenPechanec commented you can try this method which demonstrate here.

Prevent Style Change of Button

I initially set background of button with this code at onCreateView.
uc.setBackgroundResource(R.drawable.saat_button_none);
If I initially set background or textColor of button I want to prevent style change when I use onClick
public void onClick(View v) {
switch (v.getId()) {
case R.id.bir:
uc.setBackgroundResource(R.drawable.saat_button); //Should not work
dort.setBackgroundResource(R.drawable.saat_button_sel);
bes.setBackgroundResource(R.drawable.saat_button_sel);
}
}
Is that possible?
Edit: I don't want to use if statement since I have lots of buttons I just want to lock style of button.
To do this, create a custom view simply by extending View and override all methods related to background and put your logic their if background has changed once then overridden method should throw exception saying that you can't change the style as it has been changed while setup the default look and feel.
public class CustomButton extends Button {
boolean backgroundChanged = true;
public CustomButton(Context context) {
this(context, null);
}
public CustomButton(Context context, #Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomButton(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void setBackgroundResource(int resid) {
if(backgroundChanged){
throw new RuntimeException("you can't change the style as it has been changed while setup the default look and feel");
}
super.setBackgroundResource(resid);
}
}
At last in layout file replace <Button tag with <CustomButton

Android: Creating a custom component programmatically does not reflect the style applied

Created a custom button which extends AppCompatButton. The following are the constructors used:
public CustomButton(Context context)
{
this(context, null);
}
public CustomButton(Context context, AttributeSet attrs)
{
this(context, attrs, R.style.customStyle);
}
public CustomButton(final Context context, final AttributeSet attrs, final int defStyleAttr)
{
super(context, attrs, defStyleAttr);
}
Constructing CustomButton through XML works fine. However, when constructed in Java, it does not reflect the customStyle properties. Tried debugging the code. Though it passes through the second constructor doesn't take up the properties.
Any leads would be highly appreciated.
I was able to solve this by creating a ContextThemeWrapper object when creating CustomButton programmatically.
In activity file:
CustomButton customButton = new CustomButton( new ContextThemeWrapper(this, R.style.customStyle));

Android: How to set max to min values of numberpicker with offset of 10

I want to have number picker with values 10,20,30,40,50
when I'm doing like this:
minutePicker.setMaxValue(10);
minutePicker.setMinValue(1);
minutePicker.setDisplayedValues(values);
provided values is {"30", "40", "50", "60", "70"};
Im able to display values as expected but these are like edit text, when I'm taping on each value keyboard displays, how can I make it just display value as textview rather edit text
Create NumberPicker class like below
public class MyNumberPicker extends NumberPicker {
public MyNumberPicker(Context context, AttributeSet attrs) {
super(context, attrs);
processAttributeSet(attrs);
}
public MyNumberPicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
processAttributeSet(attrs);
}
private void processAttributeSet(AttributeSet attrs) {
//This method reads the parameters given in the xml file and sets the properties according to it
this.setMinValue(attrs.getAttributeIntValue(null, "min", 0));
this.setMaxValue(attrs.getAttributeIntValue(null, "max", 0));
}
}

Using custom font in android TextView using xml

I have added a custom font file to my assets/fonts folder. How do I use it from my XML?
I can use it from code as follows:
TextView text = (TextView) findViewById(R.id.textview03);
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Molot.otf");
text.setTypeface(tf);
Can't I do it from XML using an android:typeface="/fonts/Molot.otf" attribute?
Short answer: No. Android doesn't have built-in support for applying custom fonts to text widgets through XML.
However, there's a workaround that's not terribly difficult to implement.
First
You'll need to define your own stylable. In your /res/values folder, open/create the attrs.xml file and add a declare-styleable object like so:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FontText">
<attr name="typefaceAsset" format="string"/>
</declare-styleable>
</resources>
Second
Assuming you want to use this widget often, you should set up a simple cache for the loaded Typeface objects, since loading them from memory on the fly can take time. Something like:
public class FontManager {
private static FontManager instance;
private AssetManager mgr;
private Map<String, Typeface> fonts;
private FontManager(AssetManager _mgr) {
mgr = _mgr;
fonts = new HashMap<String, Typeface>();
}
public static void init(AssetManager mgr) {
instance = new FontManager(mgr);
}
public static FontManager getInstance() {
if (instance == null) {
// App.getContext() is just one way to get a Context here
// getContext() is just a method in an Application subclass
// that returns the application context
AssetManager assetManager = App.getContext().getAssets();
init(assetManager);
}
return instance;
}
public Typeface getFont(String asset) {
if (fonts.containsKey(asset))
return fonts.get(asset);
Typeface font = null;
try {
font = Typeface.createFromAsset(mgr, asset);
fonts.put(asset, font);
} catch (Exception e) {
}
if (font == null) {
try {
String fixedAsset = fixAssetFilename(asset);
font = Typeface.createFromAsset(mgr, fixedAsset);
fonts.put(asset, font);
fonts.put(fixedAsset, font);
} catch (Exception e) {
}
}
return font;
}
private String fixAssetFilename(String asset) {
// Empty font filename?
// Just return it. We can't help.
if (TextUtils.isEmpty(asset))
return asset;
// Make sure that the font ends in '.ttf' or '.ttc'
if ((!asset.endsWith(".ttf")) && (!asset.endsWith(".ttc")))
asset = String.format("%s.ttf", asset);
return asset;
}
}
This one will allow you to use .ttc file extensions, but it's untested.
Third
Create a new class that subclasses TextView. This particular example takes into account the defined XML typeface (bold, italic, etc.) and apply it to the font (assuming you're using a .ttc file).
/**
* TextView subclass which allows the user to define a truetype font file to use as the view's typeface.
*/
public class FontText extends TextView {
public FontText(Context context) {
this(context, null);
}
public FontText(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FontText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (isInEditMode())
return;
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.FontText);
if (ta != null) {
String fontAsset = ta.getString(R.styleable.FontText_typefaceAsset);
if (!TextUtils.isEmpty(fontAsset)) {
Typeface tf = FontManager.getInstance().getFont(fontAsset);
int style = Typeface.NORMAL;
float size = getTextSize();
if (getTypeface() != null)
style = getTypeface().getStyle();
if (tf != null)
setTypeface(tf, style);
else
Log.d("FontText", String.format("Could not create a font from asset: %s", fontAsset));
}
}
}
}
Finally
Replace the instances of TextView in your XML with the fully qualified class name. Declare your custom namespace just like you would the Android namespace. Note that the "typefaceAsset" should point to a .ttf or .ttc file contained in your /assets directory.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.FontText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is a custom font text"
custom:typefaceAsset="fonts/AvenirNext-Regular.ttf"/>
</RelativeLayout>
Here is example code that does this. I have the font defined in a static final variable and the font file is in the assets directory.
public class TextViewWithFont extends TextView {
public TextViewWithFont(Context context, AttributeSet attrs) {
super(context, attrs);
this.setTypeface(MainActivity.typeface);
}
public TextViewWithFont(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setTypeface(MainActivity.typeface);
}
public TextViewWithFont(Context context) {
super(context);
this.setTypeface(MainActivity.typeface);
}
}
Create your customed TextView belong to the font you want to use. In this class, I use a static mTypeface field to cache the Typeface (for better performance)
public class HeliVnTextView extends TextView {
/*
* Caches typefaces based on their file path and name, so that they don't have to be created every time when they are referenced.
*/
private static Typeface mTypeface;
public HeliVnTextView(final Context context) {
this(context, null);
}
public HeliVnTextView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public HeliVnTextView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
if (mTypeface == null) {
mTypeface = Typeface.createFromAsset(context.getAssets(), "HelveticaiDesignVnLt.ttf");
}
setTypeface(mTypeface);
}
}
In xml file:
<java.example.HeliVnTextView
android:id="#+id/textView1"
android:layout_width="0dp"
... />
In java class:
HeliVnTextView title = new HeliVnTextView(getActivity());
title.setText(issue.getName());
Activity implements LayoutInflater.Factory2 that provides callbacks on each created View.
It's possible to style the TextView with custom font Family attribute, load the typefaces on demand and call setTypeface on instantiated text views automatically.
Unfortunately due to the architectural relationship of Inflater instances relative to Activities and Windows the simplest approach to use custom fonts in android is to cache loaded fonts on the Application level.
The sample code base is here:
https://github.com/leok7v/android-textview-custom-fonts
<style name="Baroque" 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">#F2BAD0</item>
<item name="android:textSize">14pt</item>
<item name="fontFamily">baroque_script</item>
</style>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/custom.fonts"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
style="#style/Baroque"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/sample_text"
/>
results in
Not a good idea to use custom fonts in xml due to this fact
that is, you have to do it programmatically to avoid the memory leak!
UPDATE: https://github.com/chrisjenx/Calligraphy appears to be a
superior solution to this.
Maybe you can use reflection to inject/hack your font into the static list of available fonts when your application is created? I am interested in feedback from others if this is a really, really bad idea or if this is a great solution — it seems it is going to be one of those extremes...
I was able to inject my custom typeface into the list of system typefaces with my own font family name, then specifying that custom font family name ("brush-script") as the value of android:FontFamily on a standard TextView worked on my LG G4 running Android 6.0.
public class MyApplication extends android.app.Application
{
#Override
public void onCreate()
{
super.onCreate();
Typeface font = Typeface.createFromAsset(this.getResources().getAssets(),"fonts/brush-script.ttf");
injectTypeface("brush-script", font);
}
private boolean injectTypeface(String fontFamily, Typeface typeface)
{
try
{
Field field = Typeface.class.getDeclaredField("sSystemFontMap");
field.setAccessible(true);
Object fieldValue = field.get(null);
Map<String, Typeface> map = (Map<String, Typeface>) fieldValue;
map.put(fontFamily, typeface);
return true;
}
catch (Exception e)
{
Log.e("Font-Injection", "Failed to inject typeface.", e);
}
return false;
}
}
In my layout
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Fancy Text"
android:fontFamily="brush-script"/>
Create a fonts folder in assets and add all your required font's there.
public class CustomTextView extends TextView {
private static final String TAG = "TextView";
public CustomTextView(Context context) {
super(context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setCustomFont(context, attrs);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setCustomFont(context, attrs);
}
private void setCustomFont(Context ctx, AttributeSet attrs) {
TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.CustomTextView);
String customFont = a.getString(R.styleable.CustomTextView_customFont);
setCustomFont(ctx, customFont);
a.recycle();
}
public boolean setCustomFont(Context ctx, String fontName) {
Typeface typeface = null;
try {
if(fontName == null){
fontName = Constants.DEFAULT_FONT_NAME;
}
typeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/" + fontName);
} catch (Exception e) {
Log.e(TAG, "Unable to load typeface: "+e.getMessage());
return false;
}
setTypeface(typeface);
return true;
}
}
and add a declarable in attrs.xml
<declare-styleable name="CustomTextView">
<attr name="customFont" format="string"/>
</declare-styleable>
and then add your customFont like
app:customFont="arial.ttf"
I know this is an old question, but i've found a much easier solution.
First declare your TextView in xml as usual.
Put your font (TTF or TTC) in the asset folder
app\src\main\assets\
Then just set the typeface for your text view in your onCreate method.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_name);
TextView textView = findViewById(R.id.my_textView);
Typeface typeface = Typeface.createFromAsset(getAssets(), "fontName.ttf");
textView.setTypeface(typeface);
}
Done.
The best solution is to use (finally) introduced by Google a native custom font feature in XML. But you have to target API 26. It supports API 16+
https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml
instead of xmlns:custom="schemas.android.com/tools"; you should use: xmlns:custom="schemas.android.com/apk/res-auto"; in order to use styleable attributes.
I made this change and it is working now.
the latest update now that you can set the font in XML without any other classes added like:
android:fontFamily="#font_folder/font_file"

Categories