打造原生的图文混排控件

随着互联网的发展,信息展示的元素越来越丰富,无论是PC端,还是移动端,图文混排已经成为一种通用的信息展示方式,但在各个平台却都没有提供这种原生的控件。为了更方便地在开发中展示丰富的文本信息,便自定义了这个图文混排控件。

思想

普通的图文混排,无非就两种元素:文字和图片。根据这种特点,我们可以自定义协议,如图片的的网址以\img_url\来引用。根据这种协议就可以将整个文章进行分段,然后动态地创建控件(TextView和ImageView)加载数据即可。

协议

文本不需要协议规定,图片网址用\img_url\的形式引用(协议自己定义)。
PS:对于文章中文字部分的或要做特殊处理。

实现

根据上面的思想,将很容易实现原生的图片混排控件,我们只需要自定义一个LinearLayout, 在其中动态加载布局即可。

step1: 将文章进行分段

没错,使用正则表达式根据上面的协议便可对文章进行分段:

 private final String imageRegex = "<img>(.*?)</img>";

  /**
    * 设置图文混排控件要显示的内容
    * @param content 要显示的内容
    */
 public void setContent(String content) {
    // 格式化字符串(替换特殊符号)
    String text = null;
    // 设置子View水平居中
    setGravity(Gravity.CENTER_HORIZONTAL);
    Pattern pattern = Pattern.compile(imageRegex);
    Matcher matcher = pattern.matcher(content);
    while (matcher.find()) {
         // 加载文字
        text = content.substring(startPos, matcher.start());
        if (!TextUtils.isEmpty(text)) {
            appendTextView(clearNewlineChar(text));
        }
        // 加载图片
        appendImageView(content.substring(matcher.start() + 5, matcher.end() - 6));
        startPos = matcher.end();
    }
    // 加载最后一个图片后面的文字
    text = content.substring(startPos);
    if (!TextUtils.isEmpty(text)) {
        appendTextView(clearNewlineChar(text));
    }
}

step2: 加载分段后的文字部分

/**
 * 动态添加文本内容
 * @param content
 */
private void appendTextView(String content) {
    if (!TextUtils.isEmpty(content)) {
        TextView textView = new TextView(context);
        textView.setTextIsSelectable(true);
        textView.setText(content);
        textView.setGravity(Gravity.LEFT);
        textView.getPaint().setTextSize(42);
        textView.setLineSpacing(0, 1.4f);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        params.bottomMargin = dpToPx(12);
        params.leftMargin = dpToPx(10);
        params.rightMargin = dpToPx(10);
        textView.setLayoutParams(params);
        addView(textView);
    }
}

step3: 加载分段后的图片部分

/**
 * 动态添加图片
 * @param imageUrl
 */
private void appendImageView(String imageUrl) {
    ImageView imageView = new ImageView(context);
    final int screenWidth = getDeviceScreenWidth();
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(screenWidth, (int) (screenWidth * 2.0 / 3));
    params.bottomMargin = dpToPx(12);
    imageView.setLayoutParams(params);
    ImageLoader.getInstance().displayImage(imageUrl, imageView);
    addView(imageView);
}

源码

public class MixedTextImageLayout extends LinearLayout {

    private int startPos = 0;
    private Context context;
    private final String articleRegex =  "((<img>(.*?)</img>)|(\\{poi\\}(.*?)\\{/poi\\}))";
    private final String imageRegex = "<img>(.*?)</img>";

    public MixedTextImageLayout(Context context) {
        super(context);
        this.context = context;
        setOrientation(VERTICAL);
    }

    public MixedTextImageLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        setOrientation(VERTICAL);
    }

    public MixedTextImageLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
        setOrientation(VERTICAL);
    }

    /**
     * 设置图文混排控件要显示的内容
     * @param content 要显示的内容
     */
    public void setContent(String content) {
        // 格式化字符串(替换特殊符号)
        String text = null;
        setGravity(Gravity.CENTER_HORIZONTAL);
        Pattern pattern = Pattern.compile(imageRegex);
        Matcher matcher = pattern.matcher(clearNeedlessChars(content));
        while (matcher.find()) {
            text = content.substring(startPos, matcher.start());
            if (!TextUtils.isEmpty(text)) {
                appendTextView(clearNewlineChar(text));
            }
            appendImageView(content.substring(matcher.start() + 5, matcher.end() - 6));
            startPos = matcher.end();
        }
        text = content.substring(startPos);
        if (!TextUtils.isEmpty(text)) {
            appendTextView(clearNewlineChar(text));
        }
    }

    /**
     * 动态添加文本内容
     * @param content
     */
    private void appendTextView(String content) {
        if (!TextUtils.isEmpty(content)) {
            TextView textView = new TextView(context);
            textView.setTextIsSelectable(true);
            textView.setText(content);
            textView.setGravity(Gravity.LEFT);
            textView.getPaint().setTextSize(42);
            textView.setLineSpacing(0, 1.4f);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            params.bottomMargin = dpToPx(12);
            params.leftMargin = dpToPx(10);
            params.rightMargin = dpToPx(10);
            textView.setLayoutParams(params);
            addView(textView);
        }
    }

    /**
     * 动态添加图片
     * @param imageUrl
     */
    private void appendImageView(String imageUrl) {
        ImageView imageView = new ImageView(context);
        final int screenWidth = getDeviceScreenWidth();
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(screenWidth, (int) (screenWidth * 2.0 / 3));
        params.bottomMargin = dpToPx(12);
        imageView.setLayoutParams(params);
        ImageLoader.getInstance().displayImage(imageUrl, imageView);
        addView(imageView);
    }

    /**
     * 清除多余的字符
     * @param str
     * @return
     */
    private String clearNeedlessChars(String str) {
        str = str.replaceAll("&amp;","&");
        str = str.replaceAll("&quot;","\"");  //"
        str = str.replaceAll("&nbsp;&nbsp;","\t");// 替换跳格
        str = str.replaceAll("&nbsp;"," ");// 替换空格
        str = str.replaceAll("&lt;","<");
        str = str.replaceAll("&gt;",">");
        str = str.replaceAll("\r","");
        str = str.replaceAll("\n","");
        str = str.replaceAll("\t","");

        return str;
    }

    /**
     * 清除多余的尾部换行符 注意:replaceFirst不会替换字符串本身的内容
     * @param content
     * @return
     */
    private String clearNewlineChar(String content) {
        int startPos = 0;
        int endPos = content.length() - 1;

        // 清除文字首部多余的换行符
        while (startPos <= endPos) {
            if (content.charAt(startPos) == '\n' || content.charAt(startPos) == '\r') {
                startPos++;
                // 当所有内容都是换行符的情况
                if (startPos > endPos) {
                    content = "";
                    endPos -= startPos;
                    break;
                }
            } else {
                // 获取清除后的字符串,并重新设置尾部位置
                content = content.substring(startPos);
                endPos -= startPos;
                break;
            }
        }
        // 清除文字尾部多余的换行符
        while (endPos > 0) {
            if (content.charAt(endPos) == '\n' || content.charAt(endPos) == '\r') {
                endPos--;
            } else {
                content = content.substring(0, endPos+1);
                break;
            }
        }

        return content;
    }

    /**
     * 获取屏幕宽度
     * @return
     */
    public int getDeviceScreenWidth() {
        DisplayMetrics dm = getResources().getDisplayMetrics();
        int w = dm.widthPixels;
        int h = dm.heightPixels;
        return w > h ? h : w;
    }

    /**
     * dp转px
     * @param dp
     * @return
     */
    public int dpToPx(int dp) {
        return (int) (getResources().getDisplayMetrics().density * ((float) dp)+0.5);
    }
}

使用

在布局文件中定义之后,代码中直接调用setContent()方法设置内容即可。

 mixedLayout = (MixedTextImageLayout) findViewById(R.id.mixed_layout);
 mixedLayout.setContent(content);

效果

这里写图片描述

总结

其实图文混排有多种方式可以实现,最常用的可能就是直接用WebView加载了,简单易用且样式丰富,但是对移动端而言,交互相对较难。所以具体使用哪种方式,还是要根据需求进行取舍。当然,这种方式除了加载文字和图片之外,也可以加载其他布局(需要对代码进行扩展)。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Delphi是一种编程语言和开发环境,可以用于创建各种类型的应用程序,包括图形用户界面应用程序。在Delphi中,可以使用图文混排来在应用程序中同时显示文本和图像。 要在Delphi中实现图文混排,可以使用TRichEdit组件。TRichEdit可以显示富文本,包括文字、图像、链接和其他格式化元素。通过在RichEdit控件中插入图像,可以将图像和文字混合显示。 首先,您需要在Delphi的开发环境中添加TRichEdit组件。然后,在代码中使用RichEdit对象的方法和属性来控制文本和图像的插入和格式化。 要插入图像,可以使用RichEdit对象的InsertGraphic方法。该方法需要一个TPicture对象作为参数,TPicture对象可以从文件中加载图像或通过其他方式创建。 除了图像,您还可以通过RichEdit对象的InsertText方法插入和格式化文本。可以使用该方法将纯文本或富文本字符串插入到控件中,并设置字体、颜色、大小和其他格式属性。 在将文本和图像插入RichEdit控件后,可以通过代码更改它们的位置、大小和样式。例如,可以使用RichEdit对象的Selection、Paragraph和Range属性来选择特定的文本或图像,并设置其格式。 通过将文本和图像混排显示在Delphi应用程序中,可以增强用户界面的可视化效果,并提供更丰富的信息展示方式。无论是创建个人笔记应用程序、富文本编辑器还是其他类型的应用程序,Delphi都提供了易于使用和灵活的工具来实现图文混排功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值