前言
这已经是Android UI 绘制过程浅析系列文章的第五篇了,不出意外的话也是最后一篇。再次声明一下,这一系列文章,是我在拜读了csdn大牛郭霖的博客文章《带你一步步深入了解View》后进行的实践。
前面依次了解了inflate的过程,以及绘制View的三个步骤:measure, layout, draw。这一次来亲身实践一下,通过自定义View来加深对这几个过程的理解。
自定义View的分类
根据实现方式,自定义View可以分为以下3种类型。
- 自绘控件。View的绘制代码(onDraw)由开发者自己完成。
- 组合控件。类似Java中的组合,将SDK提供的多个View合成为一个。
- 继承控件。类似Java中的继承,为SDK的某个控件增添新的功能。
自绘控件
自绘控件需要我们实现onDraw的绘制方法。这里做了一个小demo,RockPaperScissorView。当用户点击View时,随机出现石头/布/剪刀中的一种手势。为了简化,没有采用图片展示,而是用的文字。
RockPaperScissorView.java
public class RockPaperScissorView extends View implements View.OnClickListener { private Paint mPaint; private static final String[] GESTURES = {"Rock", "Paper", "Scissor"}; private Random rand = new Random(System.currentTimeMillis()); private String mText; private Rect mBounds; public RockPaperScissorView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mBounds = new Rect(); mText = "click me plz..."; super.setOnClickListener(this); } @Override protected void onDraw(Canvas canvas) { mPaint.setColor(Color.GREEN); // 背景色 canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint); mPaint.setColor(Color.RED); mPaint.setTextSize(100); // 文字颜色、大小 mPaint.getTextBounds(mText, 0, mText.length(), mBounds); float textWidth = mBounds.width(); float textHeight = mBounds.height(); canvas.drawText(mText, getWidth() / 2 - textWidth / 2, getHeight() / 2 + textHeight / 2, mPaint); } private void setText (String s) { mText = s; super.invalidate(); } @Override public void onClick(View v) { setText(GESTURES[rand.nextInt(GESTURES.length)]); }
自定义View需要实现onClickListener接口,不要忘了在构造函数中setOnClickListener(this)。在Canvas.drawText中,参数决定的开始绘制的点是文本的左下角,故通过 canvas.drawText(mText, getWidth()/2 - textWidth/2, getHeight()/2 + textHeight/2, mPaint) 来控制居中。截图如下:(动图技能尚未get)
组合控件
SDK提供了Button、TextView、ImageView等等一系列基础的控件,当我们需要一个比较复杂且通用的控件时,可以将这些基础控件组装起来,构成自己的组合控件。
下面实现一个简单的小demo,实现了通讯录联系人的一行样式,包含头像(ImageView)、姓名(TextView)、电话号码(TextView)。首先是布局文件。
simple_contact.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/sky_blue" android:padding="10dp"> <ImageView android:id="@+id/avatar" android:layout_width="100dp" android:layout_height="100dp" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:src="@drawable/liangjingru" /> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@id/avatar" android:layout_marginLeft="6dp" android:layout_toRightOf="@id/avatar" android:text="梁静茹" android:textColor="@color/black" android:textSize="@dimen/text_size_34" /> <TextView android:id="@+id/phone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/name" android:layout_below="@id/name" android:layout_marginTop="10dp" android:text="093132520" android:textColor="@color/black" android:textSize="@dimen/text_size_24" /> </RelativeLayout>
布局文件画出来是这个样子的: