美文网首页
Android 自定义字体,字替换为图片

Android 自定义字体,字替换为图片

作者: KennethYo | 来源:发表于2015-12-03 14:54 被阅读126次

    不久前开发的版本中有这样一个需求,根据服务器返回的分数,显示分数,各位可能觉得这有什么呢?那么请看下图。





    没错,这就是我们的需求。


    思路一,

    添加字体库,通过设置 TextView,在初始化的时候设置我们的字体。例如:

    TextView textView = (TextView) findViewById(R.id.custom);
    // 将字体文件保存在assets/fonts/目录下
    Typeface typeFace =  Typeface.createFromAsset(getAssets(),"fonts/your_font_name.ttf");
    // 应用字体
    textView.setTypeface(typeFace);
    

    思路二,

    通过 自定义 View,根据分数算出每个字的位置,通过canvas 画出。通过如下方法:

    canvas.drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) 
    

    解决方案:

    按照上面的思路,我直接去找设计妹子,说能给我做成字体库吗?然后我就被抓成土豆丝了。回来我自己了解了一下做字体库,通过了解,为这几个字(0,1,2,3,4,5,6,7,8,9,分,@#%作为一个字),做字体库显然成本比较大。

    思路一不行,就思路二吧。思路麻烦在于,要分别处理,两个字(0分),三个字(60分),四个字(100分)和@#%,四种情况。

    分清了几种状态,就可以开始着手开发了,就在这时,这时,我想到,这个,这个,不就和年初看的 emoji 表情是一个意思吗,只不过换成我自己的表情而已。

    年初看的 emoji 表情,是 github 上的一个项目,其主要原理是,通过判断字符来替换相应的字符码为 emoji 图片。

    这是自定义的 TextView

    public class FaceRateTextView extends TextView {
    
        public FaceRateTextView(Context context) {
            super(context);
            init();
        }
    
    
        public FaceRateTextView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public FaceRateTextView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {
            if (!TextUtils.isEmpty(getText())) {
                setText(getText());
            }
        }
    
        @Override
        public void setText(CharSequence text, BufferType type) {
            if (!TextUtils.isEmpty(text)) {
                SpannableStringBuilder builder = new SpannableStringBuilder(text);
                FontsHandler.addFonts(getContext(), builder, (int) getTextSize(), (int) getTextSize());
                text = builder;
            }
            super.setText(text, type);
        }
    }
    

    FontsHandler,是通过正则判断字符串当中有没有要替换的字符,并且替换为 DynamicDrawableSpan。

    public class FontsHandler {
    
        private static final Map<String, Integer> mFonts = new HashMap<>(12);
    
        static {
            mFonts.put("分", R.drawable.ic_face_rate);
            mFonts.put("0", R.drawable.ic_face_rate_0);
            mFonts.put("1", R.drawable.ic_face_rate_1);
            mFonts.put("2", R.drawable.ic_face_rate_2);
            mFonts.put("3", R.drawable.ic_face_rate_3);
            mFonts.put("4", R.drawable.ic_face_rate_4);
            mFonts.put("5", R.drawable.ic_face_rate_5);
            mFonts.put("6", R.drawable.ic_face_rate_6);
            mFonts.put("7", R.drawable.ic_face_rate_7);
            mFonts.put("8", R.drawable.ic_face_rate_8);
            mFonts.put("9", R.drawable.ic_face_rate_9);
            mFonts.put("balala", R.drawable.ic_face_rate_balala);
        }
    
        public static boolean addFonts(Context context, Spannable spannable, int size, int textSize) {
            boolean hasChanges = false;
            for (Map.Entry<String, Integer> entry : mFonts.entrySet()) {
                String key = entry.getKey();
                Matcher matcher = Pattern.compile(Pattern.quote(key)).matcher(spannable);
                while (matcher.find()) {
                    boolean set = true;
                    for (FontsSpan span : spannable.getSpans(matcher.start(),
                            matcher.end(), FontsSpan.class))
                        if (spannable.getSpanStart(span) >= matcher.start()
                                && spannable.getSpanEnd(span) <= matcher.end())
                            spannable.removeSpan(span);
                        else {
                            set = false;
                            break;
                        }
                    if (set) {
                        hasChanges = true;
                        spannable.setSpan(new FontsSpan(context, entry.getValue(), size, textSize),
                                matcher.start(), matcher.end(),
                                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    }
                }
            }
            return hasChanges;
        }
    }
    

    FontsSpan 继承于DynamicDrawableSpan,主要实现替换字符为 drawable。

    public class FontsSpan extends DynamicDrawableSpan {
        private final Context mContext;
    
        private final int mResourceId;
    
        private final int mSize;
    
        private final int mTextSize;
    
        private int mHeight;
    
        private int mWidth;
    
        private int mTop;
    
        private Drawable mDrawable;
    
        private WeakReference<Drawable> mDrawableRef;
    
        public FontsSpan(Context context, int resourceId, int size, int textSize) {
            super(DynamicDrawableSpan.ALIGN_BASELINE);
            mContext = context;
            mResourceId = resourceId;
            mWidth = mHeight = mSize = size;
            mTextSize = textSize;
        }
    
        public Drawable getDrawable() {
            if (mDrawable == null) {
                try {
                    mDrawable = mContext.getResources().getDrawable(mResourceId);
                    mHeight = mSize;
                    mWidth = mHeight * mDrawable.getIntrinsicWidth() / mDrawable.getIntrinsicHeight();
                    mTop = (mTextSize - mHeight) / 2;
                    mDrawable.setBounds(0, mTop, mWidth, mTop + mHeight);
                } catch (Exception e) {
                    // swallow
                }
            }
            return mDrawable;
        }
    
        @Override
        public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
            //super.draw(canvas, text, start, end, x, top, y, bottom, paint);
            Drawable b = getCachedDrawable();
            canvas.save();
    
            int transY = bottom - b.getBounds().bottom;
            if (mVerticalAlignment == ALIGN_BASELINE) {
                transY = top + ((bottom - top) / 2) - ((b.getBounds().bottom - b.getBounds().top) / 2) - mTop;
            }
    
            canvas.translate(x, transY);
            b.draw(canvas);
            canvas.restore();
        }
    
        private Drawable getCachedDrawable() {
            if (mDrawableRef == null || mDrawableRef.get() == null) {
                mDrawableRef = new WeakReference<Drawable>(getDrawable());
            }
            return mDrawableRef.get();
        }
    }
    

    其实原理很简单,并不复杂。
    demo代码地址

    相关文章

      网友评论

          本文标题:Android 自定义字体,字替换为图片

          本文链接:https://www.haomeiwen.com/subject/aslshttx.html