Android自定义View实现HTML图文环绕效果

移动开发 Android
Android中并没有提供HTML图文环绕效果的View,最接近的算是TextView中的ImageSpan了,但并未完全实现图文环绕(图文混排)的效果。这里介绍了系统的方法和自定义View的方法。

Android中并没有提供HTML图文环绕效果的View,最接近的算是TextView中的ImageSpan了,但并未完全实现图文环绕(图文混排)的效果。

1、Android系统TextView的ImageSpan实现图文环绕

代码如下:

  1. TextView tv = new TextView ( this ) ; 
  2.         
  3. SpannableString spanStr = new SpannableString ( "掌声那历史的房间里是副经理撒旦法阿斯顿及福利费是到发顺丰" ) ; 
  4. ImageSpan imageSpan = new ImageSpan ( this, R. drawable. a ) ; 
  5. spanStr. setSpan (imageSpan, 35, Spannable. SPAN_INCLUSIVE_INCLUSIVE ) ; 
  6. tv. setText (spanStr ) ; 
  7.         
  8. setContentView (tv ) ; 

2、Android中自定义View实现图文环绕

代码如下:

  1. FloatImageText view = new FloatImageText ( this ) ; 
  2. view. setText ( "电视里发生了房间里是积分拉萨积分拉萨积分拉萨减肥啦空间  撒旦法发大水发撒旦法看完了鸡肉味容积率为热键礼物i经二路文件容量为积分拉萨解放路口上飞机撒离开房间爱水立方法拉圣诞节福禄寿" ) ; 
  3. Bitmap bm = BitmapFactory. decodeResource (getResources ( ), R. drawable. a ) ; 
  4. view. setImageBitmap (bm, 3030 ) ; 
  5.  
  6.   
  7.  
  8.   
  9. package com.orgcent.view ; 
  10.  
  11. import java.util.ArrayList ; 
  12.  
  13. import android.content.Context ; 
  14. import android.graphics.Bitmap ; 
  15. import android.graphics.Canvas ; 
  16. import android.graphics.Color ; 
  17. import android.graphics.Paint ; 
  18. import android.graphics.Rect ; 
  19. import android.graphics.Paint.FontMetrics ; 
  20. import android.util.AttributeSet ; 
  21. import android.util.DisplayMetrics ; 
  22. import android.view.View ; 
  23. /** 
  24. * 模拟CSS中的float浮动效果 
  25. */ 
  26. public class FloatImageText extends View { 
  27.     private Bitmap mBitmap ; 
  28.     private final Rect bitmapFrame = new Rect ( ) ; 
  29.     private final Rect tmp = new Rect ( ) ; 
  30.     private int mTargetDentity = DisplayMetrics. DENSITY_DEFAULT ; 
  31.     
  32.     private final Paint mPaint = new Paint ( Paint. ANTI_ALIAS_FLAG ) ; 
  33.     private String mText ; 
  34.     private ArrayList <TextLine > mTextLines ; 
  35.     private final int [ ] textSize = new int [ 2 ] ; 
  36.  
  37.     public FloatImageText ( Context context, AttributeSet attrs, int defStyle ) { 
  38.         super (context, attrs, defStyle ) ; 
  39.         init ( ) ; 
  40.     } 
  41.  
  42.     public FloatImageText ( Context context, AttributeSet attrs ) { 
  43.         super (context, attrs ) ; 
  44.         init ( ) ; 
  45.     } 
  46.  
  47.     public FloatImageText ( Context context ) { 
  48.         super (context ) ; 
  49.         init ( ) ; 
  50.     } 
  51.     
  52.     private void init ( ) { 
  53.         mTargetDentity = getResources ( ). getDisplayMetrics ( ). densityDpi ; 
  54.         mTextLines = new ArrayList <TextLine > ( ) ; 
  55.         
  56.         mPaint. setTextSize ( 14 ) ; 
  57.         mPaint. setColor ( Color. RED ) ; 
  58.         
  59.     } 
  60.     
  61.     
  62.  
  63.     @Override 
  64.     protected void onMeasure ( int widthMeasureSpec, int heightMeasureSpec ) { 
  65.         int w = 0, h = 0 ; 
  66.         //图片大小 
  67.         w += bitmapFrame. width ( ) ; 
  68.         h += bitmapFrame. height ( ) ; 
  69.         
  70.         //文本宽度 
  71.         if ( null != mText && mText. length ( ) > 0 ) { 
  72.             mTextLines. clear ( ) ; 
  73.             int size = resolveSize ( Integer. MAX_VALUE, widthMeasureSpec ) ; 
  74.             measureAndSplitText (mPaint, mText, size ) ; 
  75.             final int textWidth = textSize [ 0 ], textHeight = textSize [ 1 ] ; 
  76.             w += textWidth ; //内容宽度 
  77.             if (h < textHeight ) { //内容高度 
  78.                 h = ( int ) textHeight ; 
  79.             } 
  80.         } 
  81.         
  82.         w = Math. max (w, getSuggestedMinimumWidth ( ) ) ; 
  83.         h = Math. max (h, getSuggestedMinimumHeight ( ) ) ; 
  84.         
  85.         setMeasuredDimension ( 
  86.                 resolveSize (w, widthMeasureSpec ), 
  87.                 resolveSize (h, heightMeasureSpec ) ) ; 
  88.     } 
  89.     
  90.     @Override 
  91.     protected void onDraw ( Canvas canvas ) { 
  92.         //绘制图片 
  93.         if ( null != mBitmap ) { 
  94.             canvas. drawBitmap (mBitmap, null, bitmapFrame, null ) ; 
  95.         } 
  96.         
  97.         //绘制文本 
  98.         TextLine line ; 
  99.         final int size = mTextLines. size ( ) ; 
  100.         for ( int i = 0 ; i < size ; i ++ ) { 
  101.             line = mTextLines. get (i ) ; 
  102.             canvas. drawText (line. text, line. x, line. y, mPaint ) ; 
  103.         } 
  104.         System. out. println (mTextLines ) ; 
  105.     } 
  106.     
  107.     
  108.     public void setImageBitmap (Bitmap bm ) { 
  109.         setImageBitmap (bm, null ) ; 
  110.     } 
  111.     
  112.     public void setImageBitmap (Bitmap bm, int left, int top ) { 
  113.         setImageBitmap (bm, new Rect (left, top, 00 ) ) ; 
  114.     } 
  115.     
  116.     public void setImageBitmap (Bitmap bm, Rect bitmapFrame ) { 
  117.         mBitmap = bm ; 
  118.         computeBitmapSize (bitmapFrame ) ; 
  119.         requestLayout ( ) ; 
  120.         invalidate ( ) ; 
  121.     } 
  122.     
  123.     public void setText ( String text ) { 
  124.         mText = text ; 
  125.         requestLayout ( ) ; 
  126.         invalidate ( ) ; 
  127.     } 
  128.     
  129.     private void computeBitmapSize (Rect rect ) { 
  130.         if ( null != rect ) { 
  131.             bitmapFrame. set (rect ) ; 
  132.         } 
  133.         if ( null != mBitmap ) { 
  134.             if (rect. right == 0 && rect. bottom == 0 ) { 
  135.                 final Rect r = bitmapFrame ; 
  136.                 r. set (r. left, r. top, 
  137.                         r. left + mBitmap. getScaledHeight (mTargetDentity ), 
  138.                         r. top + mBitmap. getScaledHeight (mTargetDentity ) ) ; 
  139.             } 
  140.         } else { 
  141.              bitmapFrame. setEmpty ( ) ; 
  142.         } 
  143.     } 
  144.     
  145.     private void measureAndSplitText ( Paint p, String content, int maxWidth ) { 
  146.         FontMetrics fm = mPaint. getFontMetrics ( ) ; 
  147.         final int lineHeight = ( int ) (fm. bottom - fm. top ) ; 
  148.         
  149.         final Rect r = new Rect (bitmapFrame ) ; 
  150. //        r.inset(-5, -5); 
  151.         
  152.         final int length = content. length ( ) ; 
  153.         int start = 0, end = 0, offsetX = 0, offsetY = 0 ; 
  154.         int availWidth = maxWidth ; 
  155.         TextLine line ; 
  156.         boolean onFirst = true ; 
  157.         boolean newLine = true ; 
  158.         while (start < length ) { 
  159.             end ++; 
  160.             if (end == length ) { //剩余的不足一行的文本 
  161.                 if (start <= length - 1 ) { 
  162.                     if (newLine ) offsetY += lineHeight ; 
  163.                     line = new TextLine ( ) ; 
  164.                     line. text = content. substring (start, end - 1 ) ; 
  165.                     line. x = offsetX ; 
  166.                     line. y = offsetY ; 
  167.                     mTextLines. add (line ) ; 
  168.                 } 
  169.                 break ; 
  170.             } 
  171.             p. getTextBounds (content, start, end, tmp ) ; 
  172.             if (onFirst ) { //确定每个字符串的坐标 
  173.                 onFirst = false ; 
  174.                 final int height = lineHeight + offsetY ; 
  175.                 if (r. top >= height ) { //顶部可以放下一行文字 
  176.                     offsetX = 0 ; 
  177.                     availWidth = maxWidth ; 
  178.                     newLine = true ; 
  179.                 } else if (newLine && (r. bottom >= height && r. left >= tmp. width ( ) ) ) { //中部左边可以放文字 
  180.                     offsetX = 0 ; 
  181.                     availWidth = r. left ; 
  182.                     newLine = false ; 
  183.                 } else if (r. bottom >= height && maxWidth - r. right >= tmp. width ( ) ) { //中部右边 
  184.                     offsetX = r. right ; 
  185.                     availWidth = maxWidth - r. right ; 
  186.                     newLine = true ; 
  187.                 } else { //底部 
  188.                     offsetX = 0 ; 
  189.                     availWidth = maxWidth ; 
  190.                     if (offsetY < r. bottom ) offsetY = r. bottom ; 
  191.                     newLine = true ; 
  192.                 } 
  193.             } 
  194.             
  195.             if (tmp. width ( ) > availWidth ) { //保存一行能放置的***字符串 
  196.                 onFirst = true ; 
  197.                 line = new TextLine ( ) ; 
  198.                 line. text = content. substring (start, end - 1 ) ; 
  199.                 line. x = offsetX ; 
  200.                 mTextLines. add (line ) ; 
  201.                 if (newLine ) { 
  202.                     offsetY += lineHeight ; 
  203.                     line. y = offsetY ; 
  204.                 } else { 
  205.                     line. y = offsetY + lineHeight ; 
  206.                 } 
  207.                 
  208.                 start = end - 1 ; 
  209.             } 
  210.         } 
  211.         textSize [ 1 ] = offsetY ; 
  212.     } 
  213.     
  214.     class TextLine { 
  215.         String text ; 
  216.         int x ; 
  217.         int y ; 
  218.         
  219.         @Override 
  220.         public String toString ( ) { 
  221.             return "TextLine [text=" + text + ", x=" + x + ", y=" + y + "]" ; 
  222.         } 
  223.     } 
  224. }  

 

责任编辑:徐川 来源: OSChina
相关推荐

2016-12-26 15:25:59

Android自定义View

2016-11-16 21:55:55

源码分析自定义view androi

2021-10-26 10:07:02

鸿蒙HarmonyOS应用

2016-04-12 10:07:55

AndroidViewList

2017-03-02 13:33:19

Android自定义View

2013-05-20 17:33:44

Android游戏开发自定义View

2012-05-18 10:52:20

TitaniumAndroid模块自定义View模块

2013-03-28 10:58:30

自定义Android界android

2017-03-14 15:09:18

AndroidView圆形进度条

2013-01-09 17:22:38

Android开发Camera

2011-08-02 11:17:13

iOS开发 View

2017-04-21 14:27:21

Android控件QQ未读消息

2013-04-01 14:35:10

Android开发Android自定义x

2014-12-30 11:51:35

ListViewItem View

2009-09-07 22:00:15

LINQ自定义

2017-05-19 10:03:31

AndroidBaseAdapter实践

2022-05-18 07:44:13

自定义菜单前端

2021-09-14 15:13:18

鸿蒙HarmonyOS应用

2010-02-07 14:02:16

Android 界面

2017-05-18 12:36:16

android万能适配器列表视图
点赞
收藏

51CTO技术栈公众号