I am using a RecyclerView
to populate the data from cloud. But it looks like, setting custom font for a TextView
is not easy as its inside the view. Traditional way, this is what I tried :
TextView tx = (TextView)findViewById(R.id.person_age);
Typeface custom_font = Typeface.createFromAsset(getAssets(), "fonts/Dancing Script.ttf");
tx.setTypeface(custom_font);
But here , it crashes the app, So looking for fix, here is the code to the Main Activiy:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Parse.initialize(this, "app-id", "clientkey");
setContentView(R.layout.activity_big_board);
initializeData();
TextView tx = (TextView)findViewById(R.id.person_age);
Typeface custom_font = Typeface.createFromAsset(getAssets(), "fonts/Dancing Script.ttf");
tx.setTypeface(custom_font);
adapter = new RVAdapter(persons);
rv=(RecyclerView)findViewById(R.id.rv);
LinearLayoutManager llm = new LinearLayoutManager(this);
rv.setLayoutManager(llm);
rv.setHasFixedSize(true);
initializeAdapter();
}
private void initializeData(){
persons = new ArrayList<>();
ParseQuery<ParseObject> query = new ParseQuery<ParseObject>("BigBoard");
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> credentialList, ParseException e) {
if (e == null) {
for(int i=0;i<credentialList.size();i++)
{
a=credentialList.get(i).getString("Location");
b=credentialList.get(i).getString("Feed");
persons.add(new Person(a,b));
Log.d("OUT", "So the Val::------> " +a +b);
}
} else {
Log.d("score", "Error: " + e.getMessage());
}
adapter.notifyDataSetChanged();
}
});
}
private void initializeAdapter(){
rv.setAdapter(adapter);
}
And here is the code to the Adapter class:
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder> {
public static class PersonViewHolder extends RecyclerView.ViewHolder {
CardView cv;
TextView personName;
TextView personAge;
//ImageView personPhoto;
PersonViewHolder(View itemView) {
super(itemView);
cv = (CardView)itemView.findViewById(R.id.cv);
personName = (TextView)itemView.findViewById(R.id.person_name);
personAge = (TextView)itemView.findViewById(R.id.person_age);
//personPhoto = (ImageView)itemView.findViewById(R.id.person_photo);
}
}
List<Person> persons;
RVAdapter(List<Person> persons){
this.persons = persons;
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
@Override
public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);
PersonViewHolder pvh = new PersonViewHolder(v);
return pvh;
}
@Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
personViewHolder.personName.setText(persons.get(i).name);
personViewHolder.personAge.setText(persons.get(i).surname);
// personViewHolder.personPhoto.setImageResource(persons.get(i).photoId);
}
@Override
public int getItemCount()
{
if(persons!=null)
{
return persons.size();
}
else
{
return 0;
}
}
}
So, what's the best way to do this without causing any problems to the UI Thread? Thanks,
Move your Typeface
logic into PersonViewHolder
, probably in its constructor, for two reasons:
The TextView
exists by that point.
Your RecyclerView
probably will have more than one PersonViewHolder
, in which case you need to set the Typeface
in every PersonViewHolder
, because there will be more than one item and more than one TextView
that needs the Typeface
.
public class Adapter_Recycler_Film extends RecyclerView.Adapter<Adapter_Recycler_Film.DataViewHolder> {
private static Typeface face;
private Context mContext;
Adapter_Recycler_Film.DataViewHolder viewHolder;
public Adapter_Recycler_Film(Context context,List<String> dateData) {
........
this.mContext=context;
face = Typeface.createFromAsset(mContext.getAssets(),"fonts/IRANSansMobile(FaNum)_Medium.ttf");
}
}
public class DataViewHolder extends RecyclerView.ViewHolder {
public TextView tDate;
public DataViewHolder(View itemView) {
super(itemView);
tDate = (TextView) itemView.findViewById(R.id.txt);
if(tDate!=null){
tDate.setTypeface(face);
}
}
}
As @CommonsWare's answer is probably the most relevant to your specific case. In the perspective of efficiency, readability and hindsight I would recommend creating a custom TextView
and then assigning the TextView
to the item row of your RecyclerView
or anywhere in your application where you need a specified font for that matter.
CustomFontTextView.java
package icn.premierandroid.misc;
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;
import icn.premierandroid.R;
public class CustomFontTextView extends TextView {
AttributeSet attr;
public CustomFontTextView(Context context) {
super(context);
setCustomFont(context, attr);
}
public CustomFontTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setCustomFont(context, attrs);
}
public CustomFontTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setCustomFont(context, attrs);
}
private void setCustomFont(Context ctx, AttributeSet attrs) {
String customFont = null;
TypedArray a = null;
if (attrs != null) {
a = ctx.obtainStyledAttributes(attrs, R.styleable.CustomFontTextView);
customFont = a.getString(R.styleable.CustomFontTextView_customFont);
}
if (customFont == null) customFont = "fonts/portrait-light.ttf";
setCustomFont(ctx, customFont);
if (a != null) {
a.recycle();
}
}
public boolean setCustomFont(Context ctx, String asset) {
Typeface tf = null;
try {
tf = Typeface.createFromAsset(ctx.getAssets(), asset);
} catch (Exception e) {
Log.e("textView", "Could not get typeface", e);
return false;
}
setTypeface(tf);
return true;
}
}
values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomFontTextView">
<attr name="customFont" format="string"/>
</declare-styleable>
</resources >
Example item row for RecyclerView
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
card_view:cardUseCompatPadding="true"
card_view:cardCornerRadius="8dp">
/** Containers and other Components **/
<icn.premierandroid.misc.CustomFontTextView
android:id="@+id/comment_user_name"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:gravity="center_vertical"
android:layout_weight="0.36"/>
<icn.premierandroid.misc.CustomFontTextView
android:layout_width="0dp"
android:layout_weight="0.40"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:layout_marginStart="1dp"
android:layout_marginLeft="1dp" />
<icn.premierandroid.misc.CustomFontTextView
android:id="@+id/comment_time"
android:layout_width="0dp"
android:layout_weight="0.25"
android:gravity="center_vertical"
android:layout_height="match_parent"/>
/** Containers and other Components **/
</android.support.v7.widget.CardView>
So armed with this code, you won't need to change anything in your RecyclerView.Adapter
, RecyclerView.ViewHolder
or anywhere where you have a TextView already initialized.
Note: you can still initialize the components by using TextView textView = (TextView) findViewById(R.id.textView);
. The XML does all the work for you. Unless you are creating TextView
components programmatically then you would need to create it as CustomFontTextView textView = new CustomFontTextView();
Also you can apply the same logic to almost any components such as EditText
, Switches
, RadioButtons
, TabLayouts
etc etc
create other class which extend application
public class yourApplication extends Application {
public Typeface robotoRegular;
public Typeface robotoLight;
public Typeface robotoBold;
public Typeface robotoMedium;
@Override
public void onCreate() {
super.onCreate();
robotoRegular = Typeface.createFromAsset(this.getAssets(), getResources().getString(R.string.robotoRegular));
robotoLight = Typeface.createFromAsset(this.getAssets(), getResources().getString(R.string.robotoLight));
robotoBold = Typeface.createFromAsset(this.getAssets(), getResources().getString(R.string.robotoBold));
robotoMedium = Typeface.createFromAsset(this.getAssets(), getResources().getString(R.string.robotoMedium));
}
}
then set it to the binder
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
final String name = mDataset.get(position);
holder.txtHeader.setTypeface(((yourApplication) mContext.getApplicationContext()).robotoRegular);
holder.txtFooter.setTypeface(((yourApplication) mContext.getApplicationContext()).robotoLight);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.