I have two styles, each declaring a custom font (Normal and Bold).
<style name="label" parent="#android:style/Widget.TextView">
<item name="typeface">#string/custom_font_regular</item>
</style>
<style name="label.bold">
<item name="typeface">#string/custom_font_semibold</item>
</style>
In my xml, I set the custom TextView to use the "label" style, styling the font to normal by default. However, after a user action, I want to swap the normal font for the boldversion via the style label.bold. Is this possible? Keep in mind, I'm trying to avoid calling setTypeface(), which does not take a style as an argument but a pointer to the bold tff which seems wasteful.
Solved. Take a look at my custom textview as an example:
package com.example.ui.components;
import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;
import com.example.core.ui.R;
public class StandardTextView extends TextView {
public StandardTextView(Context context) {
this(context, null);
}
public StandardTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public StandardTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setTypeFaceFromAttributes(attrs.getStyleAttribute());
}
#Override
public void setTextAppearance(Context context, int resid) {
super.setTextAppearance(context, resid);
setTypeFaceFromAttributes(resid);
}
private void setTypeFaceFromAttributes(int attributeSet) {
if (attributeSet == -1) {
return;
}
TypedArray a = null;
try {
a = getContext().obtainStyledAttributes(attributeSet, R.styleable.StandardTextView);
if (a.getString(R.styleable.StandardTextView_typeface) == null) {
return;
}
String typeFaceString = a.getString(R.styleable.StandardTextView_typeface);
setupTypeface(typeFaceString);
} finally {
if (a != null) {
a.recycle();
}
}
}
private void setupTypeface(String typeFace) {
if (typeFace == null || "".equals(typeFace)) {
return;
}
Resources resources = getResources();
if (resources == null) {
return;
}
AssetManager assetManager = resources.getAssets();
if (assetManager == null) {
return;
}
Typeface tf = Typeface.createFromAsset(assetManager, typeFace);
setTypeface(tf);
}
}
This is how you might use it:
standardTextView.setTextAppearance(ExampleFragment.this.getActivity(), R.style.label_bold);
Attrs:
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<declare-styleable name="StandardTextView">
<attr name="typeface" format="string" />
</declare-styleable>
</resources>
Layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/default_background"
android:orientation="vertical" >
<com.example.ui.components.StandardTextView
android:id="#+id/sure_swipe_create_text"
style="#style/label"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center|top"
android:paddingTop="20dp"
android:text="#string/example" />
</RelativeLayout>
Related
How to add custom font to it?
This is my code:
public void run() {
ListAdapter adapter = new SimpleAdapter(DiaListActivity.this, diaList, R.layout.list_item, new String[]{TAG_SRNO, TAG_NAME}, new int[]{R.id.srno, R.id.name});
setListAdapter(adapter);
}
any help will be appreciated.
In R.layout.list_item layout file if you have any textview then you can set this below code::-
<com.example.TextViewPlus
android:id="#+id/textViewPlus1"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:text="#string/showingOffTheNewTypeface"
foo:customFont="saxmono.ttf">
</com.example.TextViewPlus>
Put these class file into your package:
TextViewPlus.java
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;
public class TextViewPlus extends TextView {
private static final String TAG = "TextView";
public TextViewPlus(Context context) {
super(context);
}
public TextViewPlus(Context context, AttributeSet attrs) {
super(context, attrs);
setCustomFont(context, attrs);
}
public TextViewPlus(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.TextViewPlus);
String customFont = a.getString(R.styleable.TextViewPlus_customFont);
setCustomFont(ctx, customFont);
a.recycle();
}
public boolean setCustomFont(Context ctx, String asset) {
Typeface tf = null;
try {
tf = Typeface.createFromAsset(ctx.getAssets(), asset);
} catch (Exception e) {
Log.e(TAG, "Could not get typeface: "+e.getMessage());
return false;
}
setTypeface(tf);
return true;
}
}
attrs.xml: (in res/values)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TextViewPlus">
<attr name="customFont" format="string"/>
</declare-styleable>
</resources>
What I usually do is, create a custom TextView and set it as the view of my contents,
public class CustomTextView extends TextView {
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomTextView(Context context) {
super(context);
}
public void setTypeface(Typeface tf, int style) {
if (style == Typeface.BOLD) {
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/Roboto-Regular.ttf"));
} else {
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/Roboto-Light.ttf"));
}
}
}
Now simply replace your regular TextView with the Custom one like this,
<TextView
android:id="#+id/R.id.srno"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
Into,
<com.example.CustomTextView
android:id="#+id/R.id.srno"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
This will change the normal TextView with the custom one and hence will add the font.
Note: Make sure you have crated a folder called "fonts" and put the fonts file there.
If can also customize and add different fonts just by adding a single line,
e.g. If you use,
android:textStyle="bold"
It will set the font type Roboto-Regular.ttf. Which is defined here in CustomTextView class,
if (style == Typeface.BOLD) {
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/Roboto-Regular.ttf"));
}
Got it...
#Override
public View getView(int pos, View convertView, ViewGroup parent){
View v = convertView;
if(v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.list_item, null);
}
HashMap<String,String> value = diaList.get(pos);
TextView tv = (TextView)v.findViewById(R.id.name);
Typeface custom_fontG = Typeface.createFromAsset(getAssets(), "fonts/oriya.ttf");
tv.setTypeface(custom_fontG);
tv.setText(value.get(TAG_NAME));
TextView tv2 = (TextView)v.findViewById(R.id.srno);
Typeface custom_fontH = Typeface.createFromAsset(getAssets(), "fonts/oriya.ttf");
tv2.setTypeface(custom_fontH);
tv2.setText(value.get(TAG_SRNO));
return v;
}
};
// updating listview
setListAdapter(adapter);
I am trying to use TextViewEx, (Textjustify) from here
[link] (https://github.com/bluejamesbond/TextJustify-Android )
to get text justification effect in my project but if I copy and paste the files directly to my project then the files are giving error like some thing (other files) are missing. Also I have searched for how to use TextViewEx but I got is this result below
[link] (TextViewEx, (Textjustify))
In this some one told to import the files to the root folder. What does it mean (the root folder). Also if any one has sample code that uses TextViewEx or any other easy way to justify text in Android or sample code that shows justification of text then plz help me Thanks.
Well I have struggled a lot but could not found any help to solve this problem but I have found another alternative to justify text. Use this class if one having problem with justification of text.
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
public class JustifiedTextView extends WebView {
private String core = "<html><body style='text-align:justify;color:rgba(%s);font-size:%dpx;margin: 0px 0px 0px 0px;'>%s</body></html>";
private String text;
private int textColor;
private int backgroundColor;
private int textSize;
public JustifiedTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public JustifiedTextView(Context context, AttributeSet attrs, int i) {
super(context, attrs, i);
init(attrs);
}
#SuppressWarnings("deprecation")
#SuppressLint("NewApi")
public JustifiedTextView(Context context, AttributeSet attrs, int i,
boolean b) {
super(context, attrs, i, b);
init(attrs);
}
private void init(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.JustifiedTextView);
text = a.getString(R.styleable.JustifiedTextView_text);
if (text == null)
text = "";
textColor = a.getColor(R.styleable.JustifiedTextView_textColor,
Color.BLACK);
backgroundColor = a.getColor(
R.styleable.JustifiedTextView_backgroundColor,
Color.TRANSPARENT);
textSize = a.getInt(R.styleable.JustifiedTextView_textSize, 12);
a.recycle();
this.setWebChromeClient(new WebChromeClient() {
});
reloadData();
}
public void setText(String s) {
if (s == null)
this.text = "";
else
this.text = s;
reloadData();
}
#SuppressLint("NewApi")
private void reloadData() {
if (text != null) {
String data = String
.format(core, toRgba(textColor), textSize, text);
Log.d("test", data);
this.loadDataWithBaseURL(null, data, "text/html", "utf-8", null);
}
// set WebView's background color *after* data was loaded.
super.setBackgroundColor(backgroundColor);
// Hardware rendering breaks background color to work as expected.
// Need to use software renderer in that case.
if (android.os.Build.VERSION.SDK_INT >= 11)
this.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null);
}
public void setTextColor(int hex) {
textColor = hex;
reloadData();
}
public void setBackgroundColor(int hex) {
backgroundColor = hex;
reloadData();
}
public void setTextSize(int textSize) {
this.textSize = textSize;
reloadData();
}
#SuppressLint("DefaultLocale")
private String toRgba(int hex) {
String h = Integer.toHexString(hex);
int a = Integer.parseInt(h.substring(0, 2), 16);
int r = Integer.parseInt(h.substring(2, 4), 16);
int g = Integer.parseInt(h.substring(4, 6), 16);
int b = Integer.parseInt(h.substring(6, 8), 16);
return String.format("%d,%d,%d,%d", r, g, b, a);
}
}
this is the attrib.xml class
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="JustifiedTextView">
<attr name="text" format="string" localization="suggested" />
<attr name="textColor" format="color|reference" />
<attr name="backgroundColor" format="color|reference" />
<attr name="textSize" format="integer" min="1" />
</declare-styleable>
</resources>
In the layout class use this as
<com.example.animationtest.JustifiedTextView
android:id="#+id/tjTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
app:text="Your Text Here" >
</com.example.animationtest.JustifiedTextView>
com.example.animationtest is the package name in your project where you put the file JustifiedTextView.class
In the code behind class access to the control as
JustifiedTextView tjTextView;
tvTextView2.setTextSize(convertToDp(24));
tjTextView.setTextColor(Color.RED);
tjTextView.setTextSize((int) convertFromDp(18));
where convertFromDp is used to get text size according to screen.
public float convertFromDp(int input) {
final float scale = getResources().getDisplayMetrics().density;
return ((input - 0.5f) / scale);
}
As you can see in the image above. There are three views on this screenshot.
- The first item is CheckBox with text and having state off.
- The second item is CheckBox without text and having state on.
- The last item is ImageView with src pointing to the drawable image.
The CheckBoxes were customized using android:button.
As I tried using smaller images, all of the checkbox is left-aligned.
Comparing these two images tell me that the default size of the CheckBox seems fixed to certain size until text attribute is large enough to require extending.
There is nothing special in the file as well. See following.
custom_cb.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/creditcard_selected" android:state_checked="true" />
<item android:drawable="#drawable/creditcard"/>
</selector>
layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBox android:id="#+id/cbFalse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="#drawable/custom_cb"
android:text="" />
<CheckBox android:id="#+id/cbTrue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="#drawable/custom_cb"
android:focusable="false"
android:checked="true"
android:layout_toRightOf="#id/cbFalse" />
<ImageView android:id="#+id/imvTrue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/creditcard"
android:layout_toRightOf="#id/cbTrue" />
</RelativeLayout>
Is there anyway I can use bigger image for CheckBox while keeping the size as wrap_content? If I set CheckBox layout_width to actual pixel or dp then it display full image but that mean I have to manually check for the size every time it change.
Today I had the same problem (my custom image was cutted on the left side).
I fixed it putting:
android:button="#null"
android:background="#drawable/my_custom_checkbox_state.xml"
Just use
android:button="#null"
android:background="#null"
android:drawableLeft="your custom selector"
android:drawablePadding="as you need"
android:text="your text"
Thats it.. Its working fine..
You only have to change your drawable from android:button to android:drawableLeft or android:drawableRight. And set the button to null to not show the default checkbox.
My checkbox looks like this:
<CheckBox
android:id="#+id/cb_toggle_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="#null"
android:drawableLeft="#drawable/livescore_btn_check" />
CheckBox drawables did not work for me at all, android:button and android:background gave completely erratic results and nothing could fix it.
So I wrote my own "custom checkbox".
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import org.apache.commons.lang3.StringUtils;
import butterknife.Bind;
import butterknife.ButterKnife;
import com.example.myapp.R;
/**
* Created by Zhuinden on 2015.12.02..
*/
public class CustomCheckbox
extends LinearLayout
implements View.OnClickListener {
public CustomCheckbox(Context context) {
super(context);
init(null, -1);
}
public CustomCheckbox(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, -1);
}
#TargetApi(11)
public CustomCheckbox(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
#TargetApi(21)
public CustomCheckbox(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs, defStyleAttr);
}
private void init(AttributeSet attributeSet, int defStyle) {
TypedArray a = null;
if(defStyle != -1) {
a = getContext().obtainStyledAttributes(attributeSet, R.styleable.CustomCheckbox, defStyle, 0);
} else {
a = getContext().obtainStyledAttributes(attributeSet, R.styleable.CustomCheckbox);
}
defImageRes = a.getResourceId(0, 0);
checkedImageRes = a.getResourceId(1, 0);
checked = a.getBoolean(2, false);
typeface = a.getString(3);
if(StringUtils.isEmpty(typeface)) {
typeface = "Oswald-Book.otf";
}
text = a.getString(4);
inactiveTextcolor = a.getInteger(5, android.R.color.black);
activeTextcolor = a.getInteger(6, android.R.color.red);
textsize = a.getDimensionPixelSize(7, 0);
a.recycle();
setOnClickListener(this);
if(!isInEditMode()) {
LayoutInflater.from(getContext()).inflate(R.layout.view_custom_checkbox, this, true);
ButterKnife.bind(this);
imageView.setImageResource(checked ? checkedImageRes : defImageRes);
typefaceTextView.setTypeface(typeface);
if(!StringUtils.isEmpty(text)) {
typefaceTextView.setText(text);
}
if(textsize != 0) {
typefaceTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textsize);
} else {
typefaceTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12);
}
}
}
boolean checked;
int defImageRes;
int checkedImageRes;
String typeface;
String text;
int inactiveTextcolor;
int activeTextcolor;
int textsize;
OnCheckedChangeListener onCheckedChangeListener;
#Bind(R.id.custom_checkbox_imageview)
ImageView imageView;
#Bind(R.id.custom_checkbox_text)
TypefaceTextView typefaceTextView;
#Override
protected void onFinishInflate() {
super.onFinishInflate();
}
#Override
public void onClick(View v) {
checked = !checked;
imageView.setImageResource(checked ? checkedImageRes : defImageRes);
typefaceTextView.setTextColor(checked ? activeTextcolor : inactiveTextcolor);
onCheckedChangeListener.onCheckedChanged(this, checked);
}
public void setOnCheckedChangeListener(OnCheckedChangeListener onCheckedChangeListener) {
this.onCheckedChangeListener = onCheckedChangeListener;
}
public static interface OnCheckedChangeListener {
void onCheckedChanged(View buttonView, boolean isChecked);
}
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
imageView.setImageResource(checked ? checkedImageRes : defImageRes);
typefaceTextView.setTextColor(checked ? activeTextcolor : inactiveTextcolor);
}
public void setTextColor(int color) {
typefaceTextView.setTextColor(color);
}
#Override
public Parcelable onSaveInstanceState() {
//begin boilerplate code that allows parent classes to save state
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
//end
ss.checked = this.checked;
ss.defImageRes = this.defImageRes;
ss.checkedImageRes = this.checkedImageRes;
ss.typeface = this.typeface;
ss.text = this.text;
ss.inactiveTextcolor = this.inactiveTextcolor;
ss.activeTextcolor = this.activeTextcolor;
ss.textsize = this.textsize;
return ss;
}
#Override
public void onRestoreInstanceState(Parcelable state) {
//begin boilerplate code so parent classes can restore state
if(!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
//end
this.checked = ss.checked;
this.defImageRes = ss.defImageRes;
this.checkedImageRes = ss.checkedImageRes;
this.typeface = ss.typeface;
this.text = ss.text;
this.inactiveTextcolor = ss.inactiveTextcolor;
this.activeTextcolor = ss.activeTextcolor;
this.textsize = ss.textsize;
}
static class SavedState
extends BaseSavedState {
boolean checked;
int defImageRes;
int checkedImageRes;
String typeface;
String text;
int inactiveTextcolor;
int activeTextcolor;
int textsize;
SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
this.checked = in.readByte() > 0;
this.defImageRes = in.readInt();
this.checkedImageRes = in.readInt();
this.typeface = in.readString();
this.text = in.readString();
this.inactiveTextcolor = in.readInt();
this.activeTextcolor = in.readInt();
this.textsize = in.readInt();
}
#Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeByte(this.checked ? (byte) 0x01 : (byte) 0x00);
out.writeInt(this.defImageRes);
out.writeInt(this.checkedImageRes);
out.writeString(this.typeface);
out.writeString(this.text);
out.writeInt(this.inactiveTextcolor);
out.writeInt(this.activeTextcolor);
out.writeInt(this.textsize);
}
//required field that makes Parcelables from a Parcel
public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}
Using the following attrs.xml
<resources
<declare-styleable name="CustomCheckbox">
<attr name="default_img" format="integer"/>
<attr name="checked_img" format="integer"/>
<attr name="checked" format="boolean"/>
<attr name="chx_typeface" format="string"/>
<attr name="text" format="string"/>
<attr name="inactive_textcolor" format="integer"/>
<attr name="active_textcolor" format="integer"/>
<attr name="textsize" format="dimension"/>
</declare-styleable>
</resources>
With following view_custom_checkbox.xml layout:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="#+id/custom_checkbox_imageview"
android:layout_width="#dimen/_15sdp"
android:layout_height="#dimen/_15sdp"
/>
<com.example.TypefaceTextView
android:id="#+id/custom_checkbox_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</merge>
And example:
<com.example.CustomCheckbox
android:id="#+id/program_info_record_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:clickable="true"
android:gravity="center"
app:default_img="#drawable/ic_recording_off"
app:checked_img="#drawable/ic_recording_on"
app:text="#string/record"
app:inactive_textcolor="#color/program_info_buttons_inactive"
app:active_textcolor="#color/active_color"
app:textsize="#dimen/programInfoButtonTextSize"
app:chx_typeface="SomeTypeface.otf"/>
Modify where necessary.
Try using a Linearlayout with horizontal orientation instead of RelativeLayout.Also use weight in every layout to force views to use same width.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBox android:id="#+id/cbFalse"
android:weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:button="#drawable/custom_cb"
android:text="" />
<CheckBox android:id="#+id/cbTrue"
android:weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:button="#drawable/custom_cb"
android:focusable="false"
android:checked="true"
android:layout_toRightOf="#id/cbFalse" />
<ImageView android:id="#+id/imvTrue"
android:weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="#drawable/creditcard"
android:layout_toRightOf="#id/cbTrue" />
Maybe it will be useful to someone, setting gravity attribute to center helped me to avoid image cropping:
<CheckBox
android:id="#+id/cb_accept_agreement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:button="#drawable/checkbox_selector"/>
I'm having a weird problem with TypedArray.getDrawable() in one of my custom Views. For simplicity's sake, here's a trivial test project that displays the same problem:
TestView.java
package com.example.testing;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
public class TestView extends View {
private Drawable mDrawable;
public TestView(Context context) {
this(context, null);
}
public TestView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TestView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TestView, defStyle, 0);
try {
Drawable d = a.getDrawable(R.styleable.TestView_testDrawable);
if (d != null) {
setDrawable(d);
}
} finally {
a.recycle();
}
}
private void setDrawable(Drawable d) {
mDrawable = d;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mDrawable != null) {
mDrawable.draw(canvas);
}
}
}
res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TestView">
<attr name="testDrawable" format="reference|color" />
</declare-styleable>
</resources>
res/layout/main_activity.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res/com.example.testing"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.example.testing.TestView
android:id="#+id/testView1"
android:layout_width="match_parent"
android:layout_height="100dp"
custom:testDrawable="#ff0099" />
</LinearLayout>
I'm not seeing the lovely pink rectangle (neither in the layout editor nor on an actual device). I don't understand what's wrong.
I checked your code and mDrawable is not null, but its size is -1 by -1.
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mDrawable.setBounds(0, 0, View.MeasureSpec.getSize(widthMeasureSpec), View.MeasureSpec.getSize(heightMeasureSpec));
}
this does the trick for me. I do not know if this is what you want, but maybe it's a starting point
This is how I've handled a similar case before (I modified it slightly for your code):
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TestView, defStyle, 0);
TypedValue value = a.peekValue(R.styleable.TestView_testDrawable);
if (value != null) {
if (value.type == TypedValue.TYPE_REFERENCE ||
value.type == TypedValue.TYPE_STRING) {
Drawable d = a.getDrawable(R.styleable.TestView_testDrawable);
if (d != null) {
setDrawable(d);
}
}
else
if (value.type == TypedValue.TYPE_INT_COLOR_ARGB8 ||
value.type == TypedValue.TYPE_INT_COLOR_ARGB4 ||
value.type == TypedValue.TYPE_INT_COLOR_RGB8 ||
value.type == TypedValue.TYPE_INT_COLOR_RGB4) {
Drawable d = new PaintDrawable(a.getColor(R.styleable.TestView_testDrawable, 0xFF000000));
if (d != null) {
setDrawable(d);
}
}
}
Is there any way to pass custom font for TextView (or subclasses of it) using only xml without providing any java code like this
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/CustomFont.ttf");
It is not possible to do it purely from XML, but you can create a custom view and reference that from XML. This way you will only need to write the code once, allowing you to recycle it in various layouts.
For instance, declare the class FontTextView:
package com.example;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
public class FontTextView extends TextView {
/**
* Note that when generating the class from code, you will need
* to call setCustomFont() manually.
*/
public FontTextView(Context context) {
super(context);
}
public FontTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setCustomFont(this, attrs);
}
public FontTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setCustomFont(this, attrs);
}
private void setCustomFont(Context context, AttributeSet attrs) {
if (isInEditMode()) {
// Ignore if within Eclipse
return;
}
String font = "myDefaultFont.ttf";
if (attrs != null) {
// Look up any layout-defined attributes
TypedArray a = obtainStyledAttributes(attrs,
R.styleable.FontTextView);
for (int i = 0; i < a.getIndexCount(); i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.FontTextView_customFont:
font = a.getString(attr, 0);
break;
}
}
a.recycle();
}
Typeface tf = null;
try {
tf = Typeface.createFromAsset(getAssets(), font);
} catch (Exception e) {
Log.e("Could not get typeface: " + e.getMessage());
}
setTypeface(tf);
}
}
Define the attribute in res/values/attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FontTextView">
<attr name="customFont" format="string" />
</declare-styleable>
</resources>
Use it in a layout:
Declare the namespace:
xmlns:custom="http://schemas.android.com/apk/res/com.example"
Use the FontTextView:
<com.example.FontTextView
android:id="#+id/introduction"
customFont="myCustomFont.ttf"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hello world!" />