您的位置:首页 > 移动开发 > Android开发

android-自定义View初步探索

2015-10-14 15:32 585 查看
最近开始学习自定义View,之前搞过,但是没有系统搞,从这篇博文开始系统学习自定义View。做出一些效果图展示给大家,同时写一写学些心得分享给大家。

这篇文章就是简单的一个View视图,如果你是大牛,请直接绕走,本篇对你来说太简单了。如果你自认为还不行,水平还不够,接来下请看!

首先展示效果图:



效果图非常简单,就是一个view!上面就是一个自定义view的展示!

那么实现的思路是什么呢?

将上面的图分解,中间一个圆形、一个字符串、外面有个弧形。首先分成这样的三种形状。

这么一分解就简单不少了。

首先圆形图形代码如下:

paintCir = new Paint();
paintCir.setStyle(Paint.Style.FILL);//画笔填充绘制区域
paintCir.setAntiAlias(true);//抗锯齿
paintCir.setAlpha(200);//设置透明度
paintCir.setColor(getResources().getColor(android.R.color.holo_blue_light));
//绘制圆形
canvas.drawCircle(0, 0, rr / 2, paintCir);


绘制圆形图案的代码片段如上所示。首先定义一个画笔,然后对画笔进行一些设置,最后使用画笔在canvas画布进行绘制。简单吧!!

下面对上面的代码一步步说明:

setStyle(Paint.Style.FILL) 这个是设置画笔是否填充绘制区域,Fill的意思就是填充,所以绘制的圆形是实心圆。那么空心圆如何设置呢?简单setStyle(Paint.Style.STROKE)就是。

setAntiAlias(true);//抗锯齿 一般绘制图形都会设置这个抗锯齿的效果。

setAlpha(200);//设置透明度 这个要根据实际需求进行设置。要说活命的是,这个值是从0-255之间。但是我在测试的时候,感觉没变化。设置0和设置255一样。不知道什么原因。

drawCircle(0, 0, rr / 2, paintCir)这个方法第一个和第二个参数是设置圆心x、y的坐标,第三个参数是设置圆形的半径,第四个参数就是画笔。

说明完成之后呢,就要科普一下手机屏幕的坐标系和角度坐标系是怎么回事儿了?

手机屏幕坐标系



矩形区域就是手机屏幕,x、y分别代表了横轴、数轴的正方向。这是在默认情况下,不改变坐标原点的情况下的坐标系。为什么说不改变坐标原点的情况呢?因为坐标原点可以更改。怎么改呢?

canvas.translate(width/2,height/2);

这句代码就实现坐标原点的平移,也就是更改。参数分别是在x、y轴上平移的距离。

角度坐标系



这幅图就是手机屏幕的角度坐标系,屏幕的中心不是原点,而是相对位置的原点。这么说吧,我们绘制一个view的时候,这个view有大小,有中心,这个中心可以当做角度坐标的中心原点。

明白这一点之后,对着图,0度方向水平向右,顺时针方向为正方向。逆时针方向为负方向。

这一点需要特别注意。不然后面的绘制弧形图案的时候容易脑袋混乱和抽筋!哈哈。。。

好了基础知识说明完成,下面就说一说如何实现博文开始展示的效果图,首先给出自定义view的代码:

package com.husy.mycustomview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.text.AndroidCharacter;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;

/**
* Created by husy on 2015/10/13.
*
* @link http://blog.csdn.net/u010156024 * @description:
*/
public class MyCustomView extends View{
private Paint paintTx;
private Paint paintCir;
private Paint paintArc;

public MyCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

public MyCustomView(Context context) {
super(context);
init();
}
private void init(){
paintTx = new Paint();
paintTx.setStyle(Paint.Style.STROKE);//设置画笔划线不填充
paintTx.setAntiAlias(true);//抗锯齿
paintTx.setTextSize(32);//这是字体大小
paintTx.setStrokeWidth(3);//设置画笔宽度
paintTx.setTextAlign(Paint.Align.CENTER);//设置字体对齐方式
paintTx.setColor(getResources().getColor(android.R.color.black));//设置画笔颜色

paintCir = new Paint();
paintCir.setStyle(Paint.Style.FILL);//画笔填充绘制区域
paintCir.setAntiAlias(true);//抗锯齿
paintCir.setAlpha(255);//设置透明度
paintCir.setColor(getResources().getColor(android.R.color.holo_blue_light));

paintArc = new Paint();
paintArc.setStyle(Paint.Style.STROKE);
paintArc.setAntiAlias(true);//抗锯齿
paintArc.setAlpha(127);
paintArc.setStrokeWidth(10);//设置画笔宽度
paintArc.setColor(getResources().getColor(android.R.color.holo_green_light));
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int wmode = MeasureSpec.getMode(widthMeasureSpec);
int wid = MeasureSpec.getSize(widthMeasureSpec);
int hmode = MeasureSpec.getMode(heightMeasureSpec);
int hei = MeasureSpec.getSize(heightMeasureSpec);
/*
* 此处的处理是为了当设置组件为wrap_content的时候,使用默认值大小。
* 防止出现图形混乱。
*/
if (wmode==MeasureSpec.UNSPECIFIED){
wid = 250;
}
if (hmode==MeasureSpec.UNSPECIFIED){
hei = 250;
}
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
canvas.translate(width/2,height/2);
if (width==height){

}else{
height =width;
}

//将坐标系原点移到组件中心
int rr = width/2;
String tx = "自定义View";
int len = tx.length();
//绘制圆形
canvas.drawCircle(0, 0, rr / 2, paintCir);
//绘制圆弧
float rcwidth = width*0.4f;

RectF rectF = new RectF(-rcwidth,      //left
-(height*0.4f),    //top
rcwidth,                //right
height*0.4f);      //bottom
canvas.drawRect(rectF,paintTx);
canvas.drawArc(rectF, -90, 240, false, paintArc);
//绘制文本
canvas.drawText(tx, 0, len, - len, len/4, paintTx);
canvas.save();
}
}


自定义view的代码,其中有三个构造器,一个都不能少,少了会报错!!切记!

然后init()是一个初始化的方法,分别 在三个构造器中调用进行初始化。初始化的过程中,创建了三个画笔,分别对应文章开头分析的三个图案。代码中也写了一些注释,不再说明方法的意思。

然后重写了父类的onMeasure方法,对自定义view的宽高进行了设置。在这里需要说明view的宽高。

在ViewGroup中,给View分配的空间大小并不是确定的,有可能随着具体的变化而变化,而这个变化的条件就是传到specMode中决定的,specMode一共有三种可能:

MeasureSpec.EXACTLY:父视图希望子视图的大小应该是specSize中指定的。例如设置layout_width=match_parent ,100dp,100dip 或者layout_height=match_parent ,100dp,100dip等等这些值的情况下,specMode的值就是MeasureSpec.EXACTLY

MeasureSpec.AT_MOST:子视图的大小最多是specSize中指定的值,也就是说不建议子视图的大小超过specSize中给定的值。例如,设置view的属性layout_width=wrap_content,layout_height=wrap_content 的时候,specMode的值就是MeasureSpec.AT_MOST

MeasureSpec.UNSPECIFIED:我们可以随意指定视图的大小。这种情况下view的大小不定,想多大就多大。自定义view的时候很实用。

有了上面的说明,我们就很容易理解代码中onMeasure方法的设置了。代码的意思是如果在没有指定view的大小的情况下,view大小默认宽高就是250

接下来,最后就是核心onDraw方法的重写,在onDraw方法中在画布canvas上进行绘制图案,并进行保存。

由于最终的效果中有圆形、弧形,为了绘制方便,我把原点平移到了view的中心。

canvas.translate(width/2,height/2);

这句代码就实现了这种效果。

需要说明的是,绘制圆弧的时候需要制定一个矩形区域!指定了矩形区域以后,弧形会贴着矩形区域进行绘制。请看下面的效果图:



这个效果图就把矩形区域也绘制了出来,大家可以看到弧形区域贴着矩形区域进行绘制。

同时要问问大家,能不能说出弧形区域的绘制角度???

猜到了吗?

canvas.drawArc(rectF, -90, 240, false, paintArc);

这句代码就对应上面图形的绘制角度,意思是从-90度开始,正方向绘制240度。大家好好想一想刚开始我说明的角度坐标系的问题!!!

有了自定义view之后,就可以使用了,下面给出activity的代码;

package com.husy.mycustomview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}


是不是超级简单!没错,就是这么简单粗暴!!!!哈哈。。。

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<com.husy.mycustomview.MyCustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>


引用自定义view的全类名引用到xml布局文件中就可以了。不得不提的是,android sutdio确实不错。自定义view可以在视图中进行观察,比eclipse要强!

最终的效果图,就是上面的那幅图。

下面把布局文件中改一下,如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<com.husy.mycustomview.MyCustomView
android:layout_width="200dp"
android:layout_height="200dp"
/>
</RelativeLayout>


别的地方都不变,最终的效果图如下:



是不是还可以!!哈哈。。。

好了,这个文章算是自定义view的初步实现吧,后期会加紧这方面的学习,绘制一个酷炫的效果展示出来。

代码我已经通过android studio提交到github中了,地址如下:

https://github.com/longyinzaitian/MyCustomView

大家可以通过fork或者star进自己的账号下面,通过android studio下载工程到本地,然后观看代码进行学习交流。

如果不想到github,我这里也给出下载地址,请猛戳这里!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: