Android(安卓)自定义字体,字替换为图片
16lz
2021-01-26
不久前开发的版本中有这样一个需求,根据服务器返回的分数,显示分数,各位可能觉得这有什么呢?那么请看下图。
没错,这就是我们的需求。
思路一,
添加字体库,通过设置 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代码地址
更多相关文章
- Android(安卓)CPU监控想法,思路,核心技术和代码
- Android性能优化(六)图片压缩
- MTK android CTS测试
- android osmdroid 实现谷歌地图之定位 替换为其他
- android 日常迭代与维护总结一
- 【Android】 使用okhttp实现注册登录功能(与服务器端)
- Python String 的replace()与List的remove()
- Android(安卓)深入研究layout优化
- ViewPager + Fragment 替换 TabActivity