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



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


思路一,

添加字体库,通过设置 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 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 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 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(getDrawable());        }        return mDrawableRef.get();    }}

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

更多相关文章

  1. Android(安卓)CPU监控想法,思路,核心技术和代码
  2. Android性能优化(六)图片压缩
  3. MTK android CTS测试
  4. android osmdroid 实现谷歌地图之定位 替换为其他
  5. android 日常迭代与维护总结一
  6. 【Android】 使用okhttp实现注册登录功能(与服务器端)
  7. Python String 的replace()与List的remove()
  8. Android(安卓)深入研究layout优化
  9. ViewPager + Fragment 替换 TabActivity

随机推荐

  1. Python再学习之列表介绍
  2. 如何使用 Apple Watch 控制 Mac 或 PC 上
  3. 搭建kerberos高可用集群
  4. 小技巧 | 用python给敏感信息加水印
  5. 电脑读不出移动硬盘的原因和解决办法
  6. 实战 | Pinpoint全链路监控搭建
  7. 多厂商***系列之二:Cisco&H3C GRE Over IP
  8. 直播卖货源码是什么,源码哪些功能
  9. 配置中心Apollo安装配置
  10. 娱乐一对多直播的开发周期需要多久