Android 儿童绘本/汉语拼音实现

news2024/9/22 5:41:18

有这样一个项目,开发一个电子绘本,需要在绘本上显示,汉语拼音。

界面布局

                       <androidx.core.widget.NestedScrollView
                            android:layout_width="match_parent"
                            android:layout_height="match_parent"
                            android:fillViewport="true"
                            android:padding="10dp">

                            <cn.aigcsst.student.view.PinyinTextView
                                android:id="@+id/textViewStory"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:fadeScrollbars="true"
                                android:scrollbars="vertical"
                                android:textSize="18sp" />
                        </androidx.core.widget.NestedScrollView>

实现代码

package cn.netkiller.student.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@SuppressLint("AppCompatCustomView")
public class PinyinTextView extends TextView {
    private static final String TAG = PinyinTextView.class.getSimpleName();
    private final TextPaint textPaintSpell = new TextPaint(Paint.ANTI_ALIAS_FLAG);
    private final TextPaint textPaintChinese = new TextPaint(Paint.ANTI_ALIAS_FLAG);
    private final int colorSpell = Color.parseColor("#1b97d6");
    private final int colorChinese = Color.parseColor("#000000");
    private String[] pinyin;
    private String[] chinese;

    private PlainText plainText;

    public PinyinTextView(Context context) {
        super(context);
        init();
    }

    public PinyinTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public PinyinTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public void init() {
        initTextPaint();

    }

    public void initTextPaint() {
        float denity = getResources().getDisplayMetrics().density;
        textPaintSpell.setStrokeWidth(denity);
        textPaintChinese.setStrokeWidth(denity);
        textPaintSpell.setTextAlign(Paint.Align.LEFT);
        textPaintChinese.setTextAlign(Paint.Align.LEFT);
        //设置字体大小
        textPaintSpell.setTextSize(getTextSize());
        textPaintChinese.setTextSize(getTextSize());
        textPaintSpell.setColor(colorSpell);
        textPaintChinese.setColor(colorChinese);

        textPaintSpell.setTextSize(ConvertUtils.dp2px(spellFontSize));
        textPaintChinese.setTextSize(ConvertUtils.dp2px(chineseFontSize));

    }


    private void initResource() {

        if (plainText != null) return;
        Log.d(TAG, "initResource " + getText().toString());
        String text = getText().toString();

        plainText = new PlainText();
        plainText.chinese = text;


        if (!text.isEmpty()) {
            try {
                HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
                format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
                format.setToneType(HanyuPinyinToneType.WITH_TONE_MARK);
                format.setVCharType(HanyuPinyinVCharType.WITH_U_UNICODE);

                plainText.pinyin = PinyinHelper.toHanYuPinyinString(text, format, " ", true);

                for (int index = 0; index < text.length(); index++) {
                    char character = text.charAt(index);
//                    Log.d(TAG, String.valueOf(character));

                    String[] pinyinUnit = PinyinHelper.toHanyuPinyinStringArray(character, format);

                    if (pinyinUnit == null || pinyinUnit.length == 0) {
                        plainText.character.add(new PlainTextCharacter(String.valueOf(character), String.valueOf(character)));
                    } else {
                        plainText.character.add(new PlainTextCharacter(pinyinUnit[0], String.valueOf(character)));
                    }
                }
            } catch (
                    ArrayIndexOutOfBoundsException e) {
                Log.e(TAG, Objects.requireNonNull(e.getMessage()));
            }
            Log.d(TAG, "plainText: " + plainText.character.size());
        }
//        return plainText;
    }

//    @Override
//    public boolean onPreDraw() {
//        return super.onPreDraw();
//    }


//    @Override
//    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
//        super.onLayout(changed, left, top, right, bottom);
//    }


    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        plainText = null;
    }

    @Override
    protected void onDraw(Canvas canvas) {

        initResource();

        TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setTextSize(getTextSize());
        float fontSpacing = textPaint.getFontSpacing();
        float x = 0;
        float y = fontSpacing;

        for (PlainTextCharacter c : plainText.character) {
//            Log.d(TAG, c.toString());

            float wordWidth = textPaint.measureText(c.pinyin) > textPaint.measureText(c.chinese) ? textPaint.measureText(c.pinyin) : textPaint.measureText(c.chinese);

            if (x + wordWidth > getWidth()) {
                x = 0;
                y = y + fontSpacing / 2;
            }

            float x1 = x;
            if (textPaint.measureText(c.pinyin) > textPaint.measureText(c.chinese)) {
                x1 = x + textPaint.measureText(c.pinyin) / 2 - textPaint.measureText(c.chinese) / 2;
            } else {
                x = x + textPaint.measureText(c.chinese) / 2 - textPaint.measureText(c.pinyin) / 2;
            }
            float y1 = y;

            canvas.drawText(c.pinyin, x, y, textPaintSpell);
            canvas.drawText(c.chinese, x1, y1, textPaintChinese);

            x = x + wordWidth + fontSpacing / 2;

        }
        setHeight((int) (y + fontSpacing + fontSpacing / 2));

    }
    
    public class PlainText {
        public String pinyin;
        public String chinese;
        public List<PlainTextCharacter> character = new ArrayList<PlainTextCharacter>();


    }

    public class PlainTextCharacter {
        public String pinyin;
        public String chinese;

        public PlainTextCharacter(String pinyin, String chinese) {
            this.pinyin = pinyin;
            this.chinese = chinese;
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1925360.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

路径规划 | 飞蛾扑火算法求解二维栅格路径规划(Matlab)

目录 效果一览基本介绍程序设计参考文献 效果一览 基本介绍 路径规划 | 飞蛾扑火算法求解二维栅格路径规划&#xff08;Matlab&#xff09;。 飞蛾扑火算法&#xff08;Firefly Algorithm&#xff09;是一种基于自然界萤火虫行为的优化算法&#xff0c;在路径规划问题中也可以应…

C++·多态

1. 多态的概念 多态通俗讲就是多种形态&#xff0c;就是指去完成某个行为&#xff0c;当不同对象去做时会产生不同的结果或状态。 比如买火车票这个行为&#xff0c;同样是买票的行为&#xff0c;普通成年人买到全价票&#xff0c;学生买到半价票&#xff0c;军人优先买票。这个…

Qt MV架构-视图类

一、基本概念 在MV架构中&#xff0c;视图包含了模型中的数据项&#xff0c;并将它们呈现给用户。数据项的表示方法&#xff0c;可能和数据项在存储时用的数据结构完全不同。 这种内容与表现分离之所以能够实现&#xff0c;是因为使用了 QAbstractItemModel提供的一个标准模…

Go语言---TCP服务端以及客服端的实现

TCP的C/S架构 TCP服务器的实现 监听的底层实现 func Listen(network, address string) (Listener, error) {var lc ListenConfigreturn lc.Listen(context.Background(), network, address) }type Listener interface {// Accept waits for and returns the next connection …

Jenkins中Node节点与构建任务

目录 节点在 Jenkins 中的主要作用 1. 分布式构建 分布式处理 负载均衡 2. 提供不同的运行环境 多平台支持 特殊环境需求 3. 提高资源利用率 动态资源管理 云端集成 4. 提供隔离和安全性 任务隔离 权限控制 5. 提高可扩展性 横向扩展 高可用性 Jenkins 主服务…

【深度学习入门篇 ⑤ 】PyTorch网络模型创建

【&#x1f34a;易编橙&#xff1a;一个帮助编程小伙伴少走弯路的终身成长社群&#x1f34a;】 大家好&#xff0c;我是小森( &#xfe61;ˆoˆ&#xfe61; ) &#xff01; 易编橙终身成长社群创始团队嘉宾&#xff0c;橙似锦计划领衔成员、阿里云专家博主、腾讯云内容共创官…

注册中心与配置中心,是分?是合?

一零年代初&#xff0c;我还自己动手写过socket连接来做服务注册发现&#xff0c;后来有了zookeeper就方便多了&#xff0c;那时候zookeeper也直接做配置中心使用。后来出现了一些专门的服务注册发现组件如Eureka\etcd\consul&#xff0c;专门的配置中心比如spring cloud confi…

2024年上半年信息系统项目管理师——综合知识真题题目及答案(第1批次)(2)

2024年上半年信息系统项目管理师 ——综合知识真题题目及答案&#xff08;第1批次&#xff09;&#xff08;2&#xff09; 第21题&#xff1a;在一个大型信息系统项目中&#xff0c;项目经理发现尽管已经建立了沟通机制&#xff0c;但团队间的沟通依然不畅&#xff0c;项目风险…

【JavaScript】解决 JavaScript 语言报错:Uncaught SyntaxError: Unexpected token

文章目录 一、背景介绍常见场景 二、报错信息解析三、常见原因分析1. 缺少必要的语法元素2. 使用了不正确的字符或符号3. JSON 格式错误4. 字符串未正确闭合 四、解决方案与预防措施1. 检查语法元素2. 正确使用符号和字符3. 修正 JSON 格式4. 字符串闭合 五、示例代码和实践建议…

C++基础语法:STL之迭代器

前言 "打牢基础,万事不愁" .C的基础语法的学习 引入 C基础:STL概述-CSDN博客 上一篇梳理了一些同STL有关的概念.同时对理解迭代器需要的类包含,内部类,链表等内容做了分析,这篇从<C Prime Plus> 6th Edition(以下称"本书")的P684,大标题16.4泛型编…

Sortable.js板块拖拽示例

图例 代码在图片后面 点赞❤️关注&#x1f64f;收藏⭐️ 页面加载后显示 拖拽效果 源代码 由于js库使用外链&#xff0c;所以会加载一会儿 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name&qu…

Pycharm 导入 conda 环境

使用时经常在此处卡壳&#xff0c;在此做个记录。 这个位置选择 conda 安装路径下的 python.exe 文件即可

书生浦语大模型实战营---Linux 基础知识

创建开发机 开建开发机首先填写开发机名称&#xff0c;选择镜像和配置资源&#xff0c;最后选择立即创建 ssh免密钥登陆 1、本地执行ssh-keygen -t rsa&#xff0c;然后一路回车就可以了 2、执行cat ~/.ssh/id_rsa.pub 3、回到开发机平台&#xff0c;在首页点击配置SSH Key…

手机数据恢复篇:如何从 Android 设备内恢复数据

如何从 Android 内部存储恢复数据&#xff1f; 要从 Android 内部存储恢复已删除的文件&#xff0c;您需要一个 Android 内部存储恢复应用或程序。请继续阅读以获取可靠的 Android 数据恢复软件&#xff0c;并让它帮助您从 Android 手机的内部存储恢复数据。 是否有可能恢复 An…

工业大数据是什么?应用工业大数据时面临哪些挑战?

在当今快速发展的工业领域&#xff0c;大数据已成为推动企业转型升级的核心动力。工业大数据&#xff0c;以其独特的价值和潜力&#xff0c;正逐渐改变着传统的生产、管理和决策模式。然而&#xff0c;伴随着大数据的快速发展&#xff0c;一系列挑战也随之浮现。本文将深入探讨…

刷题之单词规律同构字符串(leetcode)

同构字符串 单词规律 两个都是映射关系&#xff0c;用两张哈希表记录互相映射就可以了 同构字符串&#xff1a; class Solution { public:bool isIsomorphic(string s, string t) {//用两张哈希表做映射if(s.size()!t.size()){return false;}unordered_map<char,char&…

零基础学JS之APIS

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

算法day04 位运算 插入排序 二分法 对数器

位运算: 1&#xff09;有一个数组只包含这样的数&#xff0c;有几个数出现偶数次&#xff0c;有1个数出现奇数次&#xff0c;要求时间复杂度不超过o(n),怎么求出现奇数次的数。 使用 ^ 异或运算整个数组&#xff0c;偶数次运算结果为0&#xff0c;只留下最后一个奇数次的数。 …

【零基础】学JS之APIS第四天

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

网络层重点协议—IP协议

在复杂的网络环境中确定一个合适的路径 协议头格式如下&#xff1a; 4位版本号(version) 指定协议的版本&#xff08;IPV4-4,IPV6-6&#xff09; 4位首部长度(header length) IP头部的长度是多少个32bit&#xff0c;也就是length*4的字节数。4bit表示最大的数字是15&#x…