简体   繁体   中英

How to set Custom Font for a TextView in RecyclerView?

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:

  1. The TextView exists by that point.

  2. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM