El teleprompter de Android implementa un estilo de texto enriquecido

premisa

Hice un programa hace tiempo, una APP de teleprompter, combinado con greendao para guardar datos. Recientemente, se ha agregado un requisito para realizar la visualización de texto enriquecido. El maestro encontró un SDK en línea, pero siempre había problemas al integrarlo, y no quería mover el proyecto, se sentía muy problemático, así que construí uno relativamente bajo. El proceso fue paso a paso, y el efecto final fue muy bajo.

representaciones

Revisé la implementación de texto enriquecido en Android, principalmente la clase SpannableStringBuilder, mi idea es obtener el texto seleccionado y luego establecer directamente el formato de texto enriquecido y mostrarlo.

Ideas de diseño

primer paso:

La configuración del menú después de seleccionar el texto en EditText usa setCustomSelectionActionModeCallback

el código se muestra a continuación:

//选择文本的菜单
        text.setCustomSelectionActionModeCallback(new ActionMode.Callback2() {
           //Callback2()接口要求SDK>23 android6以上的设备 也可以实现Callback()接口

          @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                MenuInflater menuInflater = mode.getMenuInflater();
                menuInflater.inflate(R.menu.selection_menu, menu);
                return true;//返回false不会显示弹窗
            }

            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                selectionStart = text.getSelectionStart();
                selectionEnd = text.getSelectionEnd();
                text.requestFocus();
                if (selectionStart != selectionEnd) {
                    //选择的字体
                    charSequence = text.getText().subSequence(selectionStart, selectionEnd);
                }
                return false;
            }

            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.menu_add:
                        //设置字体增大
                        break;
                    case R.id.menu_dec:
                        //设置字体减小
                        break;
                    case R.id.menu_red:
                        //红色字体
                        break;
                    case R.id.menu_blue:
                        //蓝色字体
                        break;
                    case R.id.menu_black:
                        //黑色字体
                        break;
                }
                return false;//返回true系统默认的菜单选项会不见
            }

            @Override
            public void onDestroyActionMode(ActionMode mode) {

            }
        });

segundo paso

Establecer estilo de texto enriquecido

//创建富文本对象
SpannableStringBuilder str=new SpannableStringBuilder(textAll);
//将要设置的整体文本加载进来
str =  textAll = text.getText().toString();
//设置字体的大小 start是起始角标 end是结束角标
str.setSpan(new AbsoluteSizeSpan(font), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
//设置字体颜色
ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(color);
str.setSpan(foregroundColorSpan, start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

//应用字体
 text.setText(str, TextView.BufferType.SPANNABLE);

Pensé que esto estaría bien, pero esto provocó que el estilo de texto enriquecido anterior se borrara cada vez que actualizaba, y luego usé greendao para guardar los atributos de texto enriquecido. Una tabla de datos, que corresponde a varios atributos: página página, coordenadas de inicio, coordenadas de finalización, tamaño del texto, color del texto. De esta manera, cada vez que se configure uno, se almacenará como un objeto. Este objeto está vinculado a la página. Al hacer clic para ingresar a una página diferente, consultará cuántos objetos de atributo tiene la página según la página, y luego configúrelo en str.Luego sale setText.

tercer paso

El estilo de texto enriquecido está vinculado a greendao, el código principal es así

clase de gestión de greendao

public class DetailManger {

    private static final String TAG = "DetailManger";

    private static final String dbName = "detail.db";
    private final Context context;
    private DetailBeanDao dao;

    private DaoMaster.DevOpenHelper openHelper;
    public static DaoSession daoSession;

    private static DetailManger mInstance;

    private DetailManger(Context context){
        this.context = context;
        openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
        Database db = openHelper.getWritableDb();
        daoSession = new DaoMaster(db).newSession();


        DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
        DaoSession daoSession = daoMaster.newSession();
         dao = daoSession.getDetailBeanDao();

    }

    //单例
    public static DetailManger getInstance(Context context){
        if (mInstance==null){
            synchronized (DetailManger.class){
                if (mInstance==null){
                    mInstance=new DetailManger(context);
                }
            }
        }
        return mInstance;
    }
    //可读数据库
    private SQLiteDatabase getReadableDatabase() {
        if (openHelper == null) {
            openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
        }
        SQLiteDatabase db = openHelper.getReadableDatabase();
        return db;
    }

    //可写数据库
    private SQLiteDatabase getWritableDatabase() {
        if (openHelper == null) {
            openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
        }
        SQLiteDatabase db = openHelper.getWritableDatabase();
        return db;
    }

    //插入
    public void insert(DetailBean detailBean) {

        dao.insert(detailBean);
    }


    //删除数据
    public void delete(DetailBean detailBean) {

        dao.delete(detailBean);
    }

    //更改
    public void update(DetailBean detailBean) {


        dao.update(detailBean);
    }

    //查询
    public ArrayList<DetailBean> query() {

        QueryBuilder<DetailBean> qb = dao.queryBuilder();
        ArrayList<DetailBean> list = (ArrayList<DetailBean>) qb.list();
//        for (int i = 0; i < list.size(); i++) {
//            list.get(i).setIsFlush(false);
//        }
        return list;
    }

    public ArrayList<DetailBean> queryByPage(int page){
        return (ArrayList<DetailBean>) dao.queryBuilder().where(DetailBeanDao.Properties.Page.eq(page)).list();
    }
}

Después de cada clic, guarde el estilo recién establecido, léalo nuevamente y actualice todo el texto enriquecido

            
                 case R.id.menu_add:
                        //设置字体增大
                        if (charSequence != null) {
                            saveState(page, selectionStart, selectionEnd, size*2, Color.BLACK);//保存数据
                            readState(page);
                        }
                    break;


    //保存富文本样式
    private void saveState(int page, int start, int end, int font, int color) {
        SpannableStringBuilder str;
        textAll = text.getText().toString();
        DetailBean bean = new DetailBean();
        bean.setPage(page);
        bean.setStart(start);
        bean.setEnd(end);
        bean.setFont(font);
        bean.setColor(color);
        DetailManger.getInstance(MainActivity.this).insert(bean);
        Log.d(TAG, "saveState: " + bean.getPage() + " " + bean.getStart() + " " + bean.getEnd() + " " + bean.getFont() + " " + bean.getColor());

        str = new SpannableStringBuilder(textAll);

        str.setSpan(new AbsoluteSizeSpan(font), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(color);
        str.setSpan(foregroundColorSpan, start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
        readState(page);
    }


    //读取显示富文本样式
    private void readState(int page) {
        SpannableStringBuilder str;
        textAll = text.getText().toString();
        ArrayList<DetailBean> detailBeans = DetailManger.getInstance(MainActivity.this).queryByPage(page);
        str = new SpannableStringBuilder(textAll);
        for (int j = 0; j < detailBeans.size(); j++) {
            DetailBean bean = detailBeans.get(j);
            int start = bean.getStart();
            int end = bean.getEnd();
            int font = bean.getFont();
            int color = bean.getColor();
            if (selectionStart == bean.getStart() && selectionEnd == bean.getEnd()) {
                Log.d(TAG, "readState: 1111111");
            }

            if (str!=null){
                str.setSpan(new AbsoluteSizeSpan(font), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(color);
                str.setSpan(foregroundColorSpan, start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
            }


        }
        text.setText(str, TextView.BufferType.SPANNABLE);

    }

Y cada vez que ingresa por primera vez a la aplicación, cuando hace clic en una página diferente y después de modificar las opciones del menú, puede llamar al método readState().

En esta etapa, siento que el diseño es muy bajo. ¿Tienen algún buen método? ! !

Resumen de la configuración de texto enriquecido

//创建一个SpannableString对象
sStr = new SpannableString("文本文本文本文本文本文本文本文本文本文本文本文本");

//设置字体(default,default-bold,monospace,serif,sans-serif)
sStr.setSpan(new TypefaceSpan("default"), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sStr.setSpan(new TypefaceSpan("default-bold"), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sStr.setSpan(new TypefaceSpan("monospace"), 4, 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sStr.setSpan(new TypefaceSpan("serif"), 6, 8, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sStr.setSpan(new TypefaceSpan("sans-serif"), 8, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

//设置字体大小(绝对值,单位:像素),第二个参数boolean dip,如果为true,表示前面的字体大小单位为dip,否则为像素
sStr.setSpan(new AbsoluteSizeSpan(20), 10, 12, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sStr.setSpan(new AbsoluteSizeSpan(20, true), 12, 14, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

//设置字体大小(相对值,单位:像素) 参数表示为默认字体大小的多少倍 ,0.5表示一半
sStr.setSpan(new RelativeSizeSpan(0.5f), 14, 16, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

//设置字体前景色
sStr.setSpan(new ForegroundColorSpan(Color.RED), 16, 18, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

//设置字体背景色
sStr.setSpan(new BackgroundColorSpan(Color.CYAN), 18, 20, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

//设置字体样式: NORMAL正常,BOLD粗体,ITALIC斜体,BOLD_ITALIC粗斜体
sStr.setSpan(new StyleSpan(android.graphics.Typeface.NORMAL), 20, 21, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sStr.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 21, 22, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sStr.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 22, 23, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sStr.setSpan(new StyleSpan(android.graphics.Typeface.BOLD_ITALIC), 23, 24, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

//设置下划线
sStr.setSpan(new UnderlineSpan(), 24, 26, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

//设置删除线
sStr.setSpan(new StrikethroughSpan(), 26, 28, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

//设置上下标
sStr.setSpan(new SubscriptSpan(), 28, 30, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sStr.setSpan(new SuperscriptSpan(), 30, 32, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

//设置字体大小(相对值,单位:像素) 参数表示为默认字体宽度的多少倍 ,2.0f表示默认字体宽度的两倍,即X轴方向放大为默认字体的两倍,而高度不变
sStr.setSpan(new ScaleXSpan(2.0f), 32, 34, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

//设置项目符号
sStr.setSpan(new BulletSpan(android.text.style.BulletSpan.STANDARD_GAP_WIDTH,Color.GREEN), 0 ,sStr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //第一个参数表示项目符号占用的宽度,第二个参数为项目符号的颜色

//设置图片
Drawable drawable = getResources().getDrawable(R.drawable.ic_launcher);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
sStr.setSpan(new ImageSpan(drawable), 24, 26, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

tv.setText(sStr);
tv.setMovementMethod(LinkMovementMethod.getInstance());

sStr2 = new SpannableString("电话邮件百度一下短信彩信进入地图");
//超级链接(需要添加setMovementMethod方法附加响应)
sStr2.setSpan(new URLSpan("tel:8008820"), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //电话
sStr2.setSpan(new URLSpan(" mailto:[email protected](new URLSpan("mailto:[email protected]"), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //邮件
sStr2.setSpan(new URLSpan(" http://www.baidu.com"), 4, 8, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //网络
sStr2.setSpan(new URLSpan("sms:10086"), 8, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //短信 使用sms:或者smsto:
sStr2.setSpan(new URLSpan("mms:10086"), 10, 12, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

//彩信 使用mms:或者mmsto:
sStr2.setSpan(new URLSpan("geo:32.123456,-17.123456"), 12, 16, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //地图

Supongo que te gusta

Origin blog.csdn.net/m0_56366502/article/details/129398598
Recomendado
Clasificación