开发中常常会碰到这种需求,图文混排的显示方式,实现方式很简单,比如在布局文件中添加 android:drawableXXX="" 属性(这里的XX代表上下左右4个方向), 也可以在代码中添加,txt.setCompoundDrawablesWithIntrinsicBounds 这样都可以为文本添加图片,但这种方法缺陷在于,不能控制图片大小,写出来的效果往往达不到要求。直接自定义view显得复杂了点,这里推荐一种非常简单,实用的方法,就是自己通过Android自己的控件,把TextView和ImageView整合到一起。
既然要自定义新控件自然要选择android的视图来重写,这里并不是去重写view,而是viewgroup。

实现方法

自定义的viewgroup可以继承Relativelayout,Linearlayout 这里选择的是去继承Relativelayout 因为相对布局有位置设置更加自由,方便。

public class TextImageView extends RelativeLayout{    private TextView txt;    private ImageView img;    public TextImageView(Context context) {        this(context,null);    }    public TextImageView(Context context, AttributeSet attrs) {        super(context, attrs);        txt = new TextView(context,attrs);        img = new ImageView(context,attrs);        //定义图片的大小为100dp        int imgSize =(int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,100,getResources().getDisplayMetrics());        RelativeLayout.LayoutParams imgParams = new RelativeLayout.LayoutParams(imgSize,imgSize);        RelativeLayout.LayoutParams txtParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);        //设置上方边距让文字显示在图片的下方        txtParams.topMargin = imgSize;        this.addView(img,imgParams);        this.addView(txt,txtParams);   }

要实现RelativeLayout 起码需要实现的2个构造方法 public TextImageView(Context context)public TextImageView(Context context, AttributeSet attrs) ,其中只有context 上下文一个参数的方法用于在代码中new出视图,有2个参数的构造方法会去读取布局文件中的属性(这一点需要特别注意),来转化为视图,同时Xml中的属性会读取到AttributeSet attrs中。还需要注意这里在public TextImageView(Context context) ,构造方法中使用了 this()来调用实际干活的方法,这样可以确保能在xml布局文件中来实现自定义的控件。如果好奇的话可以将上面的this()改成 super() 试试看会发生什么。
位置的摆放使用了txtParams.topMargin,通过外边距来设定文本在图片的下方。

    <com.haibuzou.textimageview.TextImageView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text = "guess who i am"        android:textColor="#000000"        android:textSize="15dp"        android:src = "@mipmap/chaoxi"/>

xml中的自定义控件中可以发现我们可以使用textview 和 imageview的传统属性 ,因为在上面的构造函数中 TextView txt = new TextView(context,attrs); 我们的控件是这样声明的,所以他自己会去用xml中的传统属性(也就是:android:text,android:src等等),来生成控件。这样就方便多了

这样一个简单的图文混排就出来了。不过即使是这样依然觉得需要自己写LayoutParams的属性还是太麻烦了,如果布局稍微复杂点还要写很多代码。ViewGroup本身就已经提供了onLayout()方法来设置控件的摆放位置,有现成的不用就太可惜了

    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        //获取图片view        View imgView = getChildAt(0);        //获取文字view         View txtView = getChildAt(1);        int imgheight = imgView.getMeasuredHeight();        int imgWidth = imgView.getMeasuredWidth();        int txtWidth = txtView.getMeasuredWidth();        int txtHeight = txtView.getMeasuredHeight();        //定义图片的位置        imgView.layout(0, 0, imgWidth, imgheight);        //定义文本的位置        txtView.layout(0, imgheight,txtWidth, imgheight+txtHeight);    }

其实onlayout的方法很好理解,就是画一个矩形,控件的位置就在这个矩形中,所以我们只需要定好矩形的对角线的2个点的坐标就可以了,同时为了实验效果去掉了txtParams.topMargin = imgSize; ,不去设定位置,接着运行一下

靠文字不见了,由于我们在xmllayout_widthlayout_height 设置的方案是wrap_content而自定义的viewgroup的测量默认只支持MeasureSpec.EXACTLY这个方案,初始化的时候我们的控件高度只有这个图片这么大,所以这里如果想让文本显示在图片下方的,文本会被画在控件之外,就无法显示了。这是控件测量的问题,只能重写一下onMeasure()方法来规定大小了

    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        // 获取ViewGroup的推荐宽高和计算模式        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int width = MeasureSpec.getSize(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int height = MeasureSpec.getSize(heightMeasureSpec);        // 计算所有childview的宽高        measureChildren(widthMeasureSpec, heightMeasureSpec);        // 计算模式是wrap_content的时候的宽高        int wrapWidth = 0;        int wrapHeight = 0;        int count = getChildCount();        for (int i = 0; i < count; i++) {            //获取每一个childview            View childView = getChildAt(i);            //获取宽高值            int viewWidth = childView.getMeasuredWidth();            int viewheight = childView.getMeasuredHeight();            //单纯的对文本和字体的宽高进行相加操作            wrapWidth += viewWidth;            wrapHeight += viewheight;        }                //当模式是MeasureSpec.AT_MOST 也就是wrap_content的时候使用计算的累加的宽度或者高度值        setMeasuredDimension(widthMode == MeasureSpec.AT_MOST ? wrapWidth                : width, heightMode == MeasureSpec.AT_MOST ? wrapHeight                : height);

测量的方法整体依然比较简单,主要为了让我们的自定义控件能够去支持wrap_content 所以在模式为wrap_content的时候把我们的图片和文本的高度加起来当做控件的高度,这样就可以显示出文本来了

最后

其实第一个构建方式已经可以满足需求,在xml传入属性,在构造函数中,设置位置。后面的onLayout,onMeasure,可以拿来熟悉一下Android的自定义ViewGroup的2个重要的方法。当然这个举例只是一个简单的例子,实际应用中还可以将所有属性写在xml配置中,然后直接使用LayoutInfalter.inflate出来 然后执行addview,这种方法留给大家自己试验。最后这个骑着羊驼的老头是谁

更多相关文章

  1. Android启动画面的实现方法
  2. 提高数倍工作效率的Android(安卓)Studio技巧
  3. Android使用SharedPreferences保存List列表数据
  4. 自定义Android组件之带图像的TextView
  5. Android事件分发机制详解(二)
  6. android(18)_数据存储与访问_SQLite数据库_使用SQLiteDatabase操
  7. 关于Sytem.gc()主动触发Android(安卓)GC
  8. android学习-动画(基本的四种动画)
  9. 设置showAsAction="always"无效的问题

随机推荐

  1. PE装到移动硬盘的数据找到办法
  2. 中了exe病毒文件夹变exe应用程序解决方法
  3. SQL查询语句
  4. 后台一 搭建项目
  5. 后台四 菜单列表
  6. markdown标记语言
  7. TP6 linux安装方法
  8. ThinkPHP的使用笔记:验证码的使用和sessio
  9. U盘插入台式电脑时显示请将磁盘插入驱动
  10. laravel-admin 初次使用安装教程