I tried to add a custom font in my app. The method creating a typeface object and putting a font in it worked. Now I want to make a class for the custom font for having a cleaner code.
CustomFont.java
public class CustomFont extends AppCompatActivity {
private final Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/Slabo.ttf");
public CustomFont(TextView textView) {
textView.setTypeface(typeface);
}
}
and now I am trying to add this font to a textview:
public class MainActivity extends AppCompatActivity {
private Typeface typeface;
private CustomFont customFont;
private TextView textview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//typeface = Typeface.createFromAsset(getAssets(), "fonts/Slabo.ttf"); // works
textview = (TextView) findViewById(R.id.textviewTest);
//textview.setTypeface(typeface); // works
customFont = new CustomFont(textview); // does not work
}
}
but if I run this project I get this exception:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.AssetManager android.content.Context.getAssets()' on a null object reference
Try This :
TextView text = (TextView) findViewById(R.id.custom_font);
Typeface font = Typeface.createFromAsset(getAssets(), "yourfont.ttf");
text.setTypeface(font);
you can make method like below in your commonUtill class for better clarification
public static void setTypeface(Context mContext, View view, VIEW_TYPE type,
TYPE_FACE face, int bold) {
View mView = view;
Typeface tface = getTypeface(mContext, face);
switch (type) {
case TEXTVIEW:
((TextView) mView).setTypeface(tface, bold);
break;
case BUTTON:
((Button) mView).setTypeface(tface, bold);
break;
case EDITTEXT:
((EditText) mView).setTypeface(tface, bold);
break;
case RADIOBUTTON:
((RadioButton) mView).setTypeface(tface, bold);
break;
case CHECKBOX:
((CheckBox) mView).setTypeface(tface, bold);
break;
case CHECKEDTEXTVIEW:
((CheckedTextView) mView).setTypeface(tface, bold);
break;
default:
break;
}
}
and create function like this
public static enum TYPE_FACE {
CALIBRI, ICON_FONT, BEBAS, AWESOME, BT, TAGLINE,
CALLIBRI, WEBLYSLEEK, WEBLYSLEEK_BOLD, ICON_FONT1
}
and your view method.
public static enum VIEW_TYPE {
TEXTVIEW, BUTTON, EDITTEXT, RADIOBUTTON, CHECKBOX, CHECKEDTEXTVIEW
}
by this way you can easily manage your code.
first of all CustomFont should not be activity.It should be normal class.
public class CustomFont {
private Typeface typeface;
public CustomFont(Context context) {
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Slabo.ttf");
}
public void setFont(TextView textView) {
textView.setTypeface(typeface);
}
}
And call it from your MainActivity
customFont = new CustomFont(this);
customFont.setFont(textview);
Create Java class like this..
public class TextViewKarlaBold extends TextView {
public TextViewKarlaBold(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public TextViewKarlaBold(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TextViewKarlaBold(Context context) {
super(context);
init();
}
public void init() {
Typeface tf = Typeface.createFromAsset(getContext().getAssets(),
"fonts/Karla-Bold.ttf");
setTypeface(tf, 1);
}
}
Use this class as View in XML
<hammerapps.views.TextViewKarlaBold // hammerapps.views is My Package name
android:id="#+id/txtVIEW"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="VIEW"
android:textColor="#color/black"
android:textSize="12dp" />
Use this library if you want your entire application in a specific font
Check here
Use Custom Textview
public class TextView extends android.widget.TextView {
Context mContext;
String str;
boolean isCorner;
//fonts
public static Typeface Font_name;
public TextView(Context context) {
super(context);
mContext=context;
initialiseFont(null);
}
public TextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext=context;
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TextView, 0, 0);
try {
str = ta.getString(R.styleable.TextView_font_family);
isCorner=ta.getBoolean(R.styleable.TextView_isCorner,false);
} finally {
ta.recycle();
}
initialiseFont(str);
}
private void initialiseFont(String font) {
if(font==null || font.equals("")){
}
else {
Font_name = Typeface.createFromAsset(mContext.getAssets(), "DroidSansFallbackanmol256.ttf");
setTypeface(Font_name);
}
}
Use attrs.xml
<declare-styleable name="TextView">
<attr name="font_family" format="string"/>
<attr name="isCorner" format="boolean"/>
</declare-styleable>
Related
I've created a custom ImageView class, and I'm trying to change the imageResource when user click on it, but I'm able to call setImageResource() from that class.
Also I'd like to store like a second imageView I mean, my custom ImageView has the same starter imageView resource, but when click on it it have to be dynamic ImageView for instance:
ImageView1 ic_launcher (user has not clicked on it)
ImageView1 ic_user (user has clicked on it)
Can you guide how to achieve this?
This is my custom ImageView class :
public class CustomImageView extends android.support.v7.widget.AppCompatImageView implements View.OnClickListener {
private View.OnClickListener clickListener;
public CustomImageView(Context context) {
super(context);
setOnClickListener(this);
}
public CustomImageView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
setOnClickListener(this);
}
public CustomImageView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOnClickListener(this);
}
#Override
public void setOnClickListener(OnClickListener l) {
if (l == this) {
super.setOnClickListener(l);
} else {
clickListener = l;
}
}
#Override
public void onClick(View v) {
//Should change the imageResource here but also I should have to change it again if user wants (to the initial one)
if (clickListener != null) {
clickListener.onClick(this);
}
}
}
A solution for a custom toggleable ImageView:
Custom attribute in values/attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ToggleImageView">
<attr name="low_img" format="reference" />
<attr name="high_img" format="reference" />
</declare-styleable>
</resources>
Custom ImageView class:
public class ToggleImageView extends AppCompatImageView implements View.OnClickListener {
private Drawable mLowDrawable, mHighDrawable;
private boolean isLow = true;
public ToggleImageView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
// Extract drawables from custom attributes
TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.ToggleImageView);
setLowDrawable(values.getDrawable(R.styleable.ToggleImageView_low_img));
setHighDrawable(values.getDrawable(R.styleable.ToggleImageView_high_img));
values.recycle();
setImageDrawable(mLowDrawable);
super.setOnClickListener(this);
}
public void setLowDrawable(Drawable drawable) {
mLowDrawable = drawable;
if (isLow)
setImageDrawable(mLowDrawable);
}
public void setHighDrawable(Drawable drawable) {
mHighDrawable = drawable;
if (!isLow)
setImageDrawable(mHighDrawable);
}
#Override
public void setOnClickListener(#Nullable OnClickListener l) {
// Do nothing to block setting listener from outer caller
}
#Override
public void onClick(View view) {
toggle();
}
public void toggle() {
isLow = !isLow;
setImageDrawable(isLow ? mLowDrawable : mHighDrawable);
}
}
Usage in xml layout:
<?xml version="1.0" encoding="utf-8" ?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/root_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.tamhuynh.testfragment.ToggleImageView
android:id="#+id/toggle_img"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
app:high_img="#mipmap/high_drawable"
app:low_img="#drawable/low_drawable"
tools:low_img="#drawable/low_drawable" />
</FrameLayout>
For setting a font to android app, I use below function:
public static void persianizer(ViewGroup viewGroup) {
int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = viewGroup.getChildAt(i);
if (child instanceof ViewGroup) {
persianizer((ViewGroup) child);
continue;
}
if (child instanceof TextView) {
((TextView) child).setTypeface(RootApp.typeface);
}
}
}
It gets the root view of a layout and then set type face for every textview child of that layout. but I think it's not a good solution.
What's the best practice for changing the font of whole application?
You can create your own Font TextView class that will extends TextView and send font according to you want, have look:
public class TypefacedTextView extends TextView {
public TypefacedTextView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.TypefacedButton);
// String fontName = styledAttrs.getString(R.styleable.TypefacedButton_font);
styledAttrs.recycle();
Typeface typeface = Typeface.createFromAsset(context.getAssets(), "fonts/" +getResources().getString(R.string.roboto_light));
setTypeface(typeface);
}
Save Your fonts file in Assets folder and get by call Typeface.createFromAsset().
Here is the TypeFaceTextview in xml:
<com.demo.TypefacedTextView
android:id="#+id/textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
</com.demo.TypefacedTextView >
Happy coding!!
try this
public class CustomTextView extends android.support.v7.widget.AppCompatTextView {
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(),
"Walkway Black.ttf");
setTypeface(tf);
}
}
and then use this CustomText view in Your layout Like :
<app.com.demo.CustomTextView
android:id="#+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="#dimen/_10dp"
android:inputType=""
android:text="#string/name"
android:textColor="#color/colorSkyBlue"
android:textSize="20sp"
android:textStyle="bold" />
I am trying to set external typeface in one of my expandable list view. I am trying like below
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
String headerTitle = (String) getGroup(groupPosition);
String headerTitleDate = (String) getGroupD(groupPosition);
if (convertView == null) {
LayoutInflater layoutInflater = (LayoutInflater) this._context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.list_group, null);
}
Typeface bold = Typeface.createFromAsset(getContext().getAssets(), "shruti.ttf");
TextView listTitle = (TextView) convertView
.findViewById(R.id.tv_listtitle);
TextView listTitleDate = (TextView) convertView
.findViewById(R.id.tv_date);
listTitle.setTypeface(null, Typeface.BOLD);
listTitle.setText(headerTitle);
listTitleDate.setTypeface(null, Typeface.BOLD);
listTitleDate.setText(headerTitleDate);
return convertView;
}
But I am getting getAssets() cannot resolved. I have tried to use it with Context and without it but not success. Can anyone please suggest me what is wrong with it ?
Thanks
You should use the view's context when doing this, since it is inside an adapter.
You can get the view's context by: view.getContext()
Replacing this line:
Typeface bold = Typeface.createFromAsset(getContext().getAssets(), "shruti.ttf");
with this:
Typeface bold = Typeface.createFromAsset(convertView.getContext().getAssets(), "shruti.ttf");
will fix the error. Hope this helps, let me know if it does.
This is how i do it
STEP 1:
I first make a customizable font class, for your case you are using shruti.ttf
public class Shruti extends TextView{
public Champagne(Context context) {
super(context);
applyCustomFont(context);
}
public Champagne(Context context, AttributeSet attrs) {
super(context, attrs);
applyCustomFont(context);
}
public Champagne(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
applyCustomFont(context);
}
private void applyCustomFont(Context context) {
Typeface customFont = FontCache.getTypeface("shruti.ttf", context);
setTypeface(customFont);
}
}
STEP 2:
Then you also include a FontCache class
public class FontCache {
private static HashMap<String, Typeface> fontCache = new HashMap<>();
public static Typeface getTypeface(String fontname, Context context) {
Typeface typeface = fontCache.get(fontname);
if (typeface == null) {
try {
typeface = Typeface.createFromAsset(context.getAssets(), fontname);
} catch (Exception e) {
return null;
}
fontCache.put(fontname, typeface);
}
return typeface;
}
}
STEP 3:
Then lastly ,you attach the customized class on to your TextView. in your xml item class like this
<company.override.huzykamz.pixsar.customization.Shruti
android:layout_width="match_parent"
android:id="#+id/post_desc"
android:layout_height="wrap_content"
android:text=""
android:textColor="#000"
android:textSize="15dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingBottom="15dp" />
NOTE:
company.override.huzykamz.pixsar.customization is just a package name example , but you just put yours.
Instead of
<TextView
android:layout_width="match_parent"
android:id="#+id/post_desc"
android:layout_height="wrap_content"
android:text=""
android:textColor="#000"
android:textSize="15dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingBottom="15dp" />
Hope it works well. This is a sure deal solution
I have listview app exploring cities each row point to diffrent city , in each city activity include button when clicked open new activity which is infinite gallery contains pics of that city , i add infinite gallery to first city and work fine , when i want to add it to the second city , it gave me red mark error in the class as follow :
1- The type InfiniteGalleryAdapter is already defined.
2-The type InfiniteGallery is already defined.
I tried to change class name with the same result, I delete R.java and eclipse rebuild it with same result. Also I unchecked the java builder from project properties and get same red mark error.
Please any help and advice will be appreciated
thanks
My Code:
public class SecondCity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Boolean customTitleSupported = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
// Set the layout to use
setContentView(R.layout.main);
if (customTitleSupported) {
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.custom_title);
TextView tv = (TextView) findViewById(R.id.tv);
Typeface face=Typeface.createFromAsset(getAssets(),"BFantezy.ttf");
tv.setTypeface(face);
tv.setText("MY PICTURES");
}
InfiniteGallery galleryOne = (InfiniteGallery) findViewById(R.id.galleryOne);
galleryOne.setAdapter(new InfiniteGalleryAdapter(this));
}
}
class InfiniteGalleryAdapter extends BaseAdapter {
**//red mark here (InfiniteGalleryAdapter)**
private Context mContext;
public InfiniteGalleryAdapter(Context c, int[] imageIds) {
this.mContext = c;
}
public int getCount() {
return Integer.MAX_VALUE;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
private LayoutInflater inflater=null;
public InfiniteGalleryAdapter(Context a) {
this.mContext = a;
inflater = (LayoutInflater)mContext.getSystemService ( Context.LAYOUT_INFLATER_SERVICE)
}
public class ViewHolder{
public TextView text;
public ImageView image;
}
private int[] images = {
R.drawable.pic_1, R.drawable.pic_2,
R.drawable.pic_3, R.drawable.pic_4,
R.drawable.pic_5
};
private String[] name = {
"This is first picture (1) " ,
"This is second picture (2)",
"This is third picture (3)",
"This is fourth picture (4)",
" This is fifth picture (5)"
};
public View getView(int position, View convertView, ViewGroup parent) {
ImageView i = getImageView();
int itemPos = (position % images.length);
try {
i.setImageResource(images[itemPos]); ((BitmapDrawable) i.getDrawable()).
setAntiAlias (true);
}
catch (OutOfMemoryError e) {
Log.e("InfiniteGalleryAdapter", "Out of memory creating imageview. Using empty view.", e);
}
View vi=convertView;
ViewHolder holder;
if(convertView==null){
vi = inflater.inflate(R.layout.gallery_items, null);
holder=new ViewHolder(); holder.text=(TextView)vi.findViewById(R.id.textView1);
holder.image=(ImageView)vi.findViewById(R.id.image);
vi.setTag(holder);
} else {
holder=(ViewHolder)vi.getTag();
}
holder.text.setText(name[itemPos]);
final int stub_id=images[itemPos];
holder.image.setImageResource(stub_id);
return vi;
}
private ImageView getImageView() {
ImageView i = new ImageView(mContext);
return i;
}
}
class InfiniteGallery extends Gallery {
**//red mark here (InfiniteGallery)**
public InfiniteGallery(Context context) {
super(context);
init();
}
public InfiniteGallery(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public InfiniteGallery(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init(){
// These are just to make it look pretty
setSpacing(25);
setHorizontalFadingEdgeEnabled(false);
}
public void setResourceImages(int[] name){
setAdapter(new InfiniteGalleryAdapter(getContext(), name));
setSelection((getCount() / 2));
}
}
You are getting those red marks as these class are already defined in one of your previous class. Java won't let have duplicate names. Also it seems you are trying to define same classes for every Actvitiy which is redundant.
Just remove the two classes completely from your SecondActivity java file as they are already defined in a previous activity. I would suggest you to make a separate package where the Adapter and InfiniteGallery are defined and kept to be reused .
public class SecondCity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Boolean customTitleSupported = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
// Set the layout to use
setContentView(R.layout.main);
if (customTitleSupported) {
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.custom_title);
TextView tv = (TextView) findViewById(R.id.tv);
Typeface face=Typeface.createFromAsset(getAssets(),"BFantezy.ttf");
tv.setTypeface(face);
tv.setText("MY PICTURES");
}
InfiniteGallery galleryOne = (InfiniteGallery) findViewById(R.id.galleryOne);
galleryOne.setAdapter(new InfiniteGalleryAdapter(this));
}
}
You might have even defined the class with the same name on some other file in the same folder. Which can cause this error.
Use Ctrl+H -> Java Search -> Search for Type
It will tell you where the duplicated class is.
I crated a datetime component but it's constructed automatically (I have it in a XML layout and I don't want to create it manually) but I need to pass a reference to an Activity in order to create dialogs. How can I achieve that? I tried a setter after findViewById but it's not a good solution...
public class DateTimeComponent extends RelativeLayout {
private Activity activity;
public DateComponent(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
// rest ommited
initFields();
}
private void initFields() {
dateEditText = (EditText) findViewById(R.id.dateEditText);
dateEditText.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
activity.showDialog(DATE_PICKER_DIALOG);
}
});
timeEditText = (EditText) findViewById(R.id.timeEditText);
timeEditText.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
activity.showDialog(TIME_PICKER_DIALOG);
}
});
}
// rest ommited
public Dialog getDatePickerDialog() {
int year = selectedDateTime.get(YEAR);
int month = selectedDateTime.get(MONTH);
int day = selectedDateTime.get(DAY_OF_MONTH);
return new DatePickerDialog(activity, onDateSetListener, year, month, day);
}
public Dialog getTimePickerDialog() {
int hour = selectedDateTime.get(HOUR_OF_DAY);
int minute = selectedDateTime.get(MINUTE);
return new TimePickerDialog(activity, onTimeSetListener, hour, minute, true);
}
private final OnDateSetListener onDateSetListener = new OnDateSetListener() {
#Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
// do something
}
};
private final OnTimeSetListener onTimeSetListener = new OnTimeSetListener() {
#Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
// do something
}
};
}
Perhaps this may help you:
Option 1:
public class DateTimeComponent extends RelativeLayout {
private Activity activity;
public DateTimeComponent(Activity act){
activity = act;
}
public void someListener() {
activity.showDialog(...);
}
}
Option 2:
public class DateTimeComponent extends RelativeLayout {
public void someListener(Activity act) {
act.showDialog(...);
}
}
Option 3:
...
private Activity activity;
public DateComponent(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
activity = (Activity) getContext();
// rest ommited
initFields();
}
...
Two ways -
Create a constructor that accepts a Context parameter, and have a (private?) class variable of type Context which you can use whenever.
Add an extra Context context parameter for every method that will be needing it. In some cases you may need to make that final.
The context your constructor receives IS an Activity. So, you can cast it to it. For example like this
MyActivity a = (MyActivity) getContext();
P.S. You do not need to store activity in your own field:
private Activity activity; // not needed
it is already stored inside and can be obtained by http://developer.android.com/reference/android/view/View.html#getContext()
PROOF
Custom text view:
public class MyTextView extends TextView {
public MyTextView(Context context) {
super(context);
setText(Integer.toString(System.identityHashCode(context)));
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setText(Integer.toString(System.identityHashCode(context)));
}
}
Activity:
public class ContextActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText( Integer.toString(System.identityHashCode(this)) );
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/textView" />
<com.inthemoon.incubation.MyTextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
The codes diplayed are identical.