Android自定义View使用总结

 

  •  

Android自定义View使用总结

2016年11月29日 16:49:19 峥嵘life 阅读数:3148 标签: android widget 自定义View 更多

个人分类: Andr图形和动画 android

版权声明:本文为博主原创文章。只要评论中留言就可以转载。 https://blog.csdn.net/wenzhi20102321/article/details/53395111

      很多人把自定义View想象得很复杂,其实一步一步的去理解记忆,它的知识点并不是很难,但是它的应用方向确实是比较多。本文先简单的介绍一下自定义View和它的使用。

一.View 的基本概念

(一)View的理解

       View是一个Android视图的基础类,这个类是用户接口的基础构件。 View 表示屏幕上的一块矩形区域,负责绘制这个区域和事件处理。 View 是所有widget类的基类,Widget 类用于创建交互式UI构件(按钮,输入框等)。 View 类的ViewGroup子类是layout的基类,Layout是一个不可见的容器,它保存着 View(或ViewGroup)并定义这些View的layout属性。 可以说View类是用户视图接口类中最重要的一个类,就像Object类是所有类的基础父类相似,不过View是针对的是视图。

(二)IDs:

        Views 有一个整数相对应,id被用于在View树中找到指定的View。可以在layout文件中 定义 一个唯一的ID, 在Activity的onCreate函数中调用findViewById来查找这个View。 在整个树内,id可以不是唯一的,但再指定的范围内查找时我们可以确信它是唯一的。比如不同的xml布局文件中可以存在相同id编号,但是同一个xml布局文件中不能存在相同的id编号。

(三)获取View的位置信息

View是一个矩形区域, 使用左&上的坐标以及长和宽可以表示一个View。我们可以使用方 法getLeft() , getTop(),getRight(),getBottom(),getWidth(),getHeight()等函数来获取其位置信息.

二.View创建概述

在API中对View的回调流程有以个详细的描述:

(一)Creation:创建流程

1.调用构造器

public View(Context context) //使用java代码创建View时的构造方法
public View(Context context, AttributeSet attrs)//在XML中配置时的构造 方法,attrs存储xml中设置的属性
上面这两个构造方法都是要重写的,哪怕只是使用其中一个。并且初始化数据在这两个构造方法都要做一遍。
2.onFinishInflate() //当View和他的所有子View从XML中解析完成后调用。 一般不怎么用!

(二)Layout:布局流程

1.onMeasure(int w, int h) //确定View和它所有的子View要求的尺寸时调用

2.onLayout(boolean change, int left, int top,int right, int button) //当这个View为其所有的子View指派一个尺寸和位置时调用

3.onSizeChanged(int w, int h, int oldw, int oldh) //当这个View的尺寸改变后调用

(四)Drawing:绘制过程(自定义View的重点方法哦)

onDraw(Canvas) //当View给定其内容时调用

(五)Event:事件流程

1.onKeyDown(int, KeyEvent)//当一个新的键按下时

2.onKeyUp(int, KeyEvent) //当一个键弹起时

3.onTrackballEvent(MotionEvent)//当滚迹球事件发生时

4.onTouchEvent(MotionEvent)//当一个触摸屏事件发生时

(五)Focus:焦点流程

1.onFocusChanged(boolean, int,Rect) //当View得到和失去焦点时调用

2.onWindowFocusChanged(boolean) //当Window包含的View得到或失去焦点时调用。

三.定制View

      为了实现一个定制View, 需要重写一些View的标准方法。 framework会调用这些方法, 并且认为这些方法应该是所有的view都有实现。 这些方法不必全部重写。
      事实上,可以只重写onDraw方法就可以了自定义View的步骤:

(一)扩展View或者View的子类。

例如:
class MyView extends View
class MyView extends TextView
class MyView extends LinearLayout
class MyView extends ViewPager
  • 1
  • 2
  • 3
  • 4
  • 5

      这些都是自定义View的扩展,比如继承了TextView可以直接使用它的方法,setText(“xxx”);setBackColor(0xf00);等等。

(二) 必须实现其中一个构造方法,一般都是实现两个。

(三)重写onDraw(canvas)方法进行绘制,整个涉及到绘制任意的图像,比如画线,画圆,画矩形等等。

(四)如需调整大小,重写onMesure,默认是全屏的。

(五)如需样式在xml中布置,自定义属性。

这相当于静态使用View,比如

  • 1
  • 2
  • 3
  • 4
  • 5

      这里在静态布局中看不出什么设置,但是在MyView中可以做很多设置,比如设置好里面的文本字体、背景、甚至里面对应控件的点击事件都是可以预先在MyView中设置好的。

四.测量布局MeasureSpec

      在View系统中,指定宽和高,以及指定布局的属性,是由MeasureSpec来封装的。

(一)下面是各个模式的标志位表示。

1.private static final int MODE_SHIFT = 30;   
2.private static final int MODE_MASK  = 0x3 << MODE_SHIFT;   
3.public static final int UNSPECIFIED = 0 << MODE_SHIFT; 
4.public static final int EXACTLY     = 1 << MODE_SHIFT;
5.public static final int AT_MOST     = 2 << MODE_SHIFT;  
  • 1
  • 2
  • 3
  • 4
  • 5

      在这个解析系统中是通过移位来存放更多的数据,现在每个数据标志位都向左移动了30位。

(二)这样表示一个View大小是很方便的,我们来看下面的方法:

1.public static int makeMeasureSpec(int size, int mode) { 
  return size + mode;  
 }  
  • 1
  • 2
  • 3

      通过这个方法就可以制作一个含有两个参数的int值,这个参数包含一个mode标志和一个宽或高的表示。

2.public static int getMode(int measureSpec) {   
    return (measureSpec & MODE_MASK);    
     }  
  • 1
  • 2
  • 3

      通过方法来获取到mode。

3. public static int getSize(int measureSpec) {  
           return (measureSpec & ~MODE_MASK);    
}  
  • 1
  • 2
  • 3

      用方法来获取高或宽的数据。

      测量这个View的高和宽。通过调用这个方法来设置View的测量后的高和宽,其最终调用的方 法是:

4.protected final void setMeasuredDimension(int measuredWidth, in t measuredHeight) { 
 mMeasuredWidth = measuredWidth; 
 mMeasuredHeight = measuredHeight;  
 mPrivateFlags |= MEASURED_DIMENSION_SET;    
       }  
  • 1
  • 2
  • 3
  • 4
  • 5

      可见其最终是将高和宽保存在mMeasuredWidth、mMeasuredHeight这两个参数中。

下面是网友对MeasureSpec的一个理解:

在自定义View和ViewGroup的时候,我们经常会遇到int型的MeasureSpec来表示一个组件的大小,这个变量里面不仅有组件的尺寸大小,还有大小的模式。

这个大小的模式,有点难以理解。在系统中组件的大小模式有三种:

1.精确模式
在这种模式下,尺寸的值是多少,那么这个组件的长或宽就是多少。

2.最大模式
这个也就是父组件,能够给出的最大的空间,当前组件的长或宽最大只能为这么大,当然也可以比这个小。

3.未指定模式
这个就是说,当前组件,可以随便用空间,不受限制。

可能有很多人想不通,一个int型整数怎么可以表示两个东西(大小模式和大小的值),
一个int类型我们知道有32位。而模式有三种,要表示三种状态,至少得2位二进制位。
于是系统采用了最高的2位表示模式:

最高两位是00的时候表示"未指定模式"。即MeasureSpec.UNSPECIFIED
最高两位是01的时候表示"'精确模式"。即MeasureSpec.EXACTLY
最高两位是11的时候表示"最大模式"。即MeasureSpec.AT_MOST


很多人一遇到位操作头就大了,为了操作简便,于是系统给我提供了一个MeasureSpec工具类。
这个工具类有四个方法和三个常量(上面所示)供我们使用:


//这个是由我们给出的尺寸大小和模式生成一个包含这两个信息的int变量,这里这个模式这个参数,传三个常量中的一个。
public static int makeMeasureSpec(int size, int mode)


//这个是得到这个变量中表示的模式信息,将得到的值与三个常量进行比较。
public static int getMode(int measureSpec)


//这个是得到这个变量中表示的尺寸大小的值。
public static int getSize(int measureSpec)


//把这个变量里面的模式和大小组成字符串返回来,方便打日志
 public static String toString(int measureSpec)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

五.常用的绘图类

      常用的绘图类是Paint 画笔,Canvas 画布,Bitmap 类和BitmapFactory。

(一)Paint类

      Paint类代表画笔,用来描述图形的颜色和风格,如线宽,颜色,透明度,和填充效果等信息,使用Paint时,需要先创建该类的对象,这可以通过该类提供的构造方法来实现。通常情况下,只需要使用无参数的构造方法来创建一个使用默认设置的Paint对象:

Panit paint=new Panint();

常用方法paint.:

  1. setARGB(int a, int r, int g, int b) 用于设置颜色,各参数值均为0~255之间的整数,分别用于表示透明度、红色、绿色和蓝色值
  2. setColor(int color) 用于设置颜色,参数color可以通过Color类提供的颜色常量指定
    3.Color.rgb(in t red,int green,int blue)方法指定颜色
  3. setAlpha(int a) 用于设置透明度,值为0~255之间的整数
  4. setAntiAlias(boolean aa) 用于指定是否使用抗锯齿功能,如果使用会使绘图速度变慢 ,但是一般图像绘制都会设置使用。
    6.setDither(boolean dither) 用于指定是否使用图像抖动处理,如果使用会使图像颜色更加平滑和饱满,更加清晰
  5. setShader(Shader shader) 用于设置渐变,可以使用LinearGradient(线性渐变)、RadialGradient(径向渐变)或 者SweepGradient(角度渐变),后面分别做详细介绍 8.setStrokeWidth(float width) 用于设置笔触的宽度 9. setStyle(Paint.Style style) 用于设置填充风格,参数值 为Style.FILL表示实心、Style.FILL_AND_STROKEStyle.STROKE表示空心 10.setTextAlign(Paint.Align align) 用于设置绘制文本时的文字对齐方式,参数值为Align.CENTERAlign.LEFTAlign.RIGHT
  6. setTextSize(float textSize) 用于设置绘制文本时的文字的大小

12.渐变的几种表示形式
(1)线性渐变
new LinearGradient(0, 0, 50, 50, Color.RED, Color.GREEN, Shader.TileMod e.MIRROR);
参数一为渐变起初点坐标x位置
参数二为y轴位置
参数三和四分别对应渐变终点
最后参数为平铺方式,这里设置为镜像

(2)径向渐变
new RadialGradient(160, 110, 50, Color.RED, Color.GREEN, Shader.TileMod e.MIRROR);
参数一,参数二为渐变圆中心坐标
参数三为半径
参数四,参数五
参数六为平铺方式

(3)角度渐变
new SweepGradient(265, 110, new int[] { Color.RED, Color.GREEN, Color.B LUE }, null);
参数一参数二为渲染中心点x,y坐标
参数三为围绕中心渲染的颜色数组,至少要有两种颜色值
参数四为相对位置的颜色数组,若为null,颜色沿渐变线均匀分布

(二)Bitmap类

      Bitmap类代表位图,它是Android系统中图像处理的最重要类之一,使用它不仅可以获取图像文件信息,进行图像剪切,旋转,缩放等操作,而且还可以指定格式保存图像文件。 Bitmap类常用的方法

1. compress(Bitmap.CompressFormat format, int quality, OutputStream stream)

用于将Bitmap对象压缩为指定格式并保存到指定的文件输出流中,简单的说就是能保存一个图片到本地。
参数一:数值可以是Bitmap.CompressFormat.PNG、Bitmap.CompressFormat. JPEG和Bitmap.Compres sFormat.WEBP
参数二:0到100,100为最大品质值,
参数三:输出流,可以是文件输出流输出保存到本地,可以是网络输出流对应的就会输出到网络中。

2.createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)

用于从源位图的指定坐标点开始,“挖取”指定宽度和高度的一块图像来创建新的Bitmap对象,并按Matrix指定规则进行变换
参数一:要被挖取的Bitmap对象
参数二三:开始挖的左边和上边的位置
参数四五:要挖宽度和高度。
参数六:一个枚举类型的配置,可以定义截到的新位图的质量

最后一个参数:filter解释:
true if the source should be filtered. Only applies if the matrix contains more than just translation.
当进行的不只是平移变换时,filter参数为true可以进行滤波处理,有助于改善新图像质量;flase时,计算机不做过滤处理。
要想imageView.setImageMatrix()方法起作用,xml得配置android:scaleType="matrix"
matrix.setRotate和matrix.postRotate的区别:
post...:平移、旋转等效果可以叠加在一起;
set...:前一种效果会消失,只有后来的操作,即它会重置Matrix
3.createBitmap(int width, int height, Bitmap.Config config) 
用于创建一个指定宽度和高度的新的Bitmap对象
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

4.createBitmap(Bitmap source, int x, int y, int width, int height)

      用于从源位图的指定坐标点开始,“挖取”指定宽度、和高度的一块图像来创建新的Bitmap对象
5.createBitmap(int[] colors, int width, int height, Bitmap.Config config)
使用颜色数组创建一个指定宽度和高度的新Bitimap对象,其中,数组元素的个数为width*height
6.createBitmap(Bitmap src) 用于使用源位图创建一个新的Bitmap对象
7. createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)用于将源位图缩放为指定宽度和高度的新的Bitmap对象
8.isRecycled() 用于判断Bitmap对象是否被回收 9.recycle() 强制回收Bitmap对象

(三)BitmapFactory类

      该类为一个工具类,用于从不同的数据源来解析,创建BitMap对象。

1.decodeFile(String pathName) 用于从给定的路径所指定的文件中解析、创建Bitmap对象

2.decodeResource(Resources res, int id) 用于根据给定的资源ID从指定的资源中解析、创建 Bitmap对象 3.decodeStream(InputStream is) 用于从指定的输入流中解析、创建Bitmap对象

      思 考 : 如 何 从 S D 卡 中 解 析 图 片 文 档 并 显 示 到 G r i d V i e w 中
String path = Environment.getExternalStorageDirectory() + “/”; 得到sdcard路径

(四)Canvas类

      通过该类提供的方法,可以绘制各种图形,如,矩形,圆形,和线条等,通常情况下,要在 Andaroid中绘图,需要先创建一个继承自View类的视图,并且在该类中重写它的 onDraw(Canvas canvas)方法,然后在显示绘图的Activity中添加该视图。

1.绘制几何图形

Android提供了强大的二维图形库,比较常用的是绘制几何图形,绘制文本,路径和图片等 比较常见的图形包括点,线,弧,圆形,矩形,在Android中,Canvas类提供了丰富的绘制几何图形的 方法,通过这些方法可以绘制出各种几何图形,常用的绘制几何图形的方法如下:

  1)填充
      drawARGB(int a, int r, int g, int b)
      drawColor(int color)
      drawRGB(int r, int g, int b)
      drawColor(int color, PorterDuff.Mode mode)
  2)几何图形
     canvas.drawArc (扇形)
     canvas.drawCircle(圆)
     canvas.drawOval(椭圆)
     canvas.drawLine(线)
     canvas.drawPoint(点)
     canvas.drawRect(矩形)
     canvas.drawRoundRect(圆角矩形)
     canvas.drawVertices(顶点)
     cnavas.drawPath(路径)
   3)图片
       canvas.drawBitmap (位图)
       canvas.drawPicture (图片)
   4)文本
       canvas.drawText
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

2.绘制文本

      在Android中,可以通过TextView来显示文本,但是,在开发游戏时,特别是开发RPG类游戏时,会包含很多文字 ,使用TextView和图片显示文本不太合适,这时,就需要通过绘制文本的方式来实 现,Canvas类提供了一系列的绘制文本的方法,

(1) drawText(String text,float x,float y, Paint paint)

参数分别是,要绘制的文本,文字的起始位置X坐标,文字起始位置的Y坐标

(2) drawPosText(String text,float[] pos Paint paint)

参数分别是,要绘制的文本,每个字符的位置,该方法已过期.

(3)文字对齐使用Paint的TextAlign(xxx);

3.绘制路径

      在Android中,提供了绘制路径的功能,绘制一条路径可以分为创建路径和绘制定义好的路径两部分创建路径: 使用android.graphics.Path类来实现,Path类包含一组矢量绘图方法,如,画圆,矩形,弧,线条 等,常用的方法如下
(1) addArc(RectF oval, float startAngle, float sweepAngle) 添加弧形的路径
(2)addCircle(float x, float y, float radius, Path.Direction dir) 添加圆形的路径 //Path.Direction类型的常量,可选值为Path.Direction.CW(顺时针)和Path.Directio n.CCW(逆时针).下面同。
(3) addOval(RectF oval, Path.Direction dir) 添加椭圆形路径
(4) addRect(RectF rect, Path.Direction dir) 12. 添加矩形路径
(5)addRoundRect(RectF rect, float rx, float ry, Path.Direction dir) 添加圆角矩形路径
(6)moveTo(float x, float y) 设置开始绘制直线的起始点
(7)lineTo(float x, float y) 在moveTo()方法设置的起始点与该方法指定的结束点之间画一条直线,如果在调用该方法之前没使用moveTo()方法设置起始点,那么将从(0,0)点开始绘制直线
(8)quadTo(float x1, float y1, float x2, float y2)
用于根据指定的的参数绘制一条线段轨迹
(9)close() 闭合路径

六.自定义属性,这个使用起来相对比较麻烦,一般不用

我们在XML布局下经常使用的id,layout_width,layout_height等等参数,那么我们如何定义自 己的属性呢?

(一)atts.xml的文件


  

     
 

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

(二)自定义属性格式和意义

1. reference       引用 
2. color           颜色 
3. boolean         布尔值 
4. dimension       尺寸值 
5. float           浮点值 
6. integer         整型值 
7. string          字符串 
8. enum            枚举值
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

(三)在布局文件中使用自定义属性

  
android:layout_height="wrap_content"
app:textColor="#f00" 
app:textSize="20dp" /> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

(四)然后我们在自定义View中实现带AttributeSet属性的构造方法,并且获取自定义值

public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
 //将属性数组提取出来 
 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.M yView); 
//获取对应的自定义属性,并且给默认值
 int textColor = a.getColor(R.styleable.MyView_textColor, 8.                 0X000000); 
 float textSize = a.getDimension(R.styleable.MyView_textSize, 36); 
//将值设置给画笔,绘画后颜色和大小就已经改变成我们自定义属性的值 
 mPaint.setTextSize(textSize); 
mPaint.setColor(textColor); 
//释放 
 ta.recycle();
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

      在执行完之后,一定要确保调用recycle() 方法。用于检索从这个结构对应于给定的属性位置 到obtainStyledAttributes中的值。

七.组合控件

      组合控件的意思就是,我们并不需要自己去绘制视图上显示的内容,而只是用系统原生的控件就好了,但我们可以将几个系统原生的控件组合到一起,这样创建出的控件就被称为组合控件。
      举个例子来说,标题栏就是个很常见的组合控件,很多界面的头部都会放置一个标题栏,标题 栏上会有个返回按钮和标题,点击按钮后就可以返回到上一个界面。
那么下面我们就来尝试去 实现这样一个标题栏控件。

(一)创建文件title_text.xml

  

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

      在这个布局文件中,我们首先定义了一个RelativeLayout作为背景布局,然后在这个布局里定 义了一个Button和一个TextView,Button就是标题栏中的返回按钮,TextView就是标题栏中 的显示的文字。

(二)接下来创建一个TitleView继承自FrameLayout,代码如下所示:

public class TitleView extends FrameLayout { 
private Button leftButton; 
private TextView titleText;  
public TitleView(Context context, AttributeSet attrs) { 
        super(context, attrs); 
//加载布局,并加入当前视图 
LayoutInflater.from(context).inflate(R.layout.title, this); 
titleText = (TextView) findViewById(R.id.title_text); 
leftButton = (Button) findViewById(R.id.button_left); 
leftButton.setOnClickListener(new OnClickListener() {
             @Override  
public void onClick(View v) { 
((Activity) getContext()).finish(); 
 }  
 });  
 } 
public void setTitleText(String text) { 
titleText.setText(text);
}  
public void setLeftButtonText(String text) { 
        leftButton.setText(text);  
    } 
    public void setLeftButtonListener(OnClickListener l) { 
       leftButton.setOnClickListener(l); 
    } 
 }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

      其中这个组合控件相对来说是比较灵活的,上面的标题和返回的文本都是可以替换的,并且返回的点击的监听事件是可以重写的。

八.绘制图片,返回的都是一个Bitmap对象

(一)drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)

用于从指定点绘制从源位图中“挖取”的一块拉伸

(二)drawBitmap(Bitmap bitmap, float left, float top, Paint paint)

用于在指定点绘制位图

(三)drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)

用于从指定点绘制从源位图中“挖取”的一块

下面是一些程序的示例…

九.一个绘制简单图形图像的示例

绘制效果:
Android自定义View使用总结_第1张图片
这里只是做各种图像绘制的展示。具体代码:

(一)创建MyView继承View

package com.example.myview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.view.View;

/**
 * 创建自定义View并使用其中的简单方法
 */

public class MyView extends View {
    public MyView(Context context) {
        super(context);
        initView();
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }



    //创建画笔
    Paint paint = new Paint();
    //设置一个圆心的点
    Point point = new Point();

    //初始化数据
    void initView() {
        //对画笔的基本设置
        //设置抗锯齿
        paint.setAntiAlias(true);
        //设置防抖动
        paint.setDither(true);
        //设置颜色
        paint.setColor(Color.RED);
        //设置透明的
        paint.setAlpha(128);
        //设置线条粗细
        paint.setStrokeWidth(10);
        point.set(getResources().getDisplayMetrics().widthPixels / 2, getResources().getDisplayMetrics().heightPixels / 2);

    }

    //View的视图绘制的回调方法
    //使用的是参数里面的canvas画板对象来进行各项操作
    RectF rectF = new RectF(10, 200, 400, 400);
    RectF rectF2 = new RectF(10, 650, 400, 800);

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制一条直线
        canvas.drawLine(10, 10, 100, 10, paint);
        //绘制多条直线
        canvas.drawLines(new float[]{10, 30, 200, 30, 10, 50, 300, 50,}, paint);
        //绘制一个实心圆(默认情况)
        canvas.drawCircle(point.x, point.y, 50, paint);
        //绘制一个点,这里的点是正方形的
        canvas.drawPoint(10, 300, paint);
        //绘制一个椭圆,参数直接写里面的一个方法对API等级有限制
        canvas.drawOval(rectF, paint);
        //绘制一个矩形
        canvas.drawRect(10, 400, 100, 600, paint);
        //绘制圆角矩形
        canvas.drawRoundRect(rectF2, 50, 50, paint);
        //绘制文本
        canvas.drawText("你好世界小姐", 0, paint.getTextSize(), paint);
        canvas.drawText("你好中心小姐", point.x, point.y, paint);
        //对画笔的其他设置
        paint.setTextSize(30);
        paint.setTextAlign(Paint.Align.CENTER);
        canvas.drawText("你好正中心小姐", point.x, point.y, paint);
        //画一个空心圆也设置画笔
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(point.x, point.y + 200, 50, paint);
        //设置画笔的渐变效果
        //线性渐变
        //  paint.setShader(new LinearGradient(10,650,200,800,Color.RED,Color.BLUE, Shader.TileMode.MIRROR));
        //径向渐变,像一个圆从圆点向四周扩散
        // paint.setShader(new RadialGradient(point.x,point.y,100,Color.BLACK,Color.YELLOW, Shader.TileMode.REPEAT));
        //角度渐变
        paint.setShader(new SweepGradient(100, 100, new int[]{Color.BLUE, Color.GREEN,Color.RED}, null));

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93

(二)调用

方法1:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

方法2:

(1)java代码

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

(2)xml文件代码:




    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

      其中使用第一个方法,整个页面都是MyView的显示,使用第二个调用方法,可以在xml布局文件内添加其他的控件。

十.简易画板的实现

      程序实现在页面上显示一个跟随手指移动的小球,并且随着小球的移动,留下绘制的路线。
效果如图所示:
Android自定义View使用总结_第2张图片
程序设计的代码:

package com.lwz.path;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * 使用小圆绘制图像
 */

public class TouchView extends View {
    public TouchView(Context context) {
        super(context);
        initView();
    }

    public TouchView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    //定义画笔
    Paint paint;
    //定义一个圆点
    PointF pointf;

    //定义路径
    Path path;

    //初始化数据
    private void initView() {
        paint = new Paint();
        paint.setDither(true);
        paint.setAntiAlias(true);
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        pointf = new PointF();

        path = new Path();
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        //绘制图像,这里绘制无数个圆点组成图像
       canvas.drawCircle(pointf.x, pointf.y, 10, paint);
        canvas.drawPath(path,paint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x=event.getX();
        float y=event.getY();

        if (event.getAction() == MotionEvent.ACTION_DOWN){
            path.moveTo(x,y);
        }
        //移动就绘制图像
        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            //设置点的坐标//这个重新绘制很重要
            pointf.set(event.getX(), event.getY());
            //绘制路径
            path.lineTo(x,y);
        }
        invalidate();

        return true;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

调用类的方法:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(new TouchView(this));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

十一.一个自定义的进度框框的显示

程序效果:
Android自定义View使用总结_第3张图片

      这里设计两个空心圆,一个圆是直接绘制好的,另一个是随着进度而进行绘制,。
这里还使用画笔绘制文字,也是随着进度而改变。

进度执行完成后的显示效果:
Android自定义View使用总结_第4张图片
程序设计的代码:

(一)自定义View的代码

package com.lwz.myprogressbar;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

/**
 * 绘制一个自定义的进度条的显示
 */

public class MyProgressBar extends View {
    public MyProgressBar(Context context) {
        super(context);
        initView();
    }

    public MyProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        //获取布局文件内的自定义属性
       /*  TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ArcProgressBar);
        //取出我们的属性
        max = a.getInt(R.styleable.ArcProgressBar_max, 100);
        progress = a.getInt(R.styleable.ArcProgressBar_progress, 0);
        //一定要释放
        a.recycle();*/

        initView();
    }

    //定义画笔
    Paint paint;
    Paint paint2;
    Paint textPaint;
    //最大的进度值
    private int max = 100;
    //当前的进度值
    private int progress = 0;
    //定义圆的中心点的x轴坐标
    int width;

    //定义圆点的坐标
    RectF oval;

    //测量布局时的回调方法
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取宽度
        width = getWidth();
        //确定圆的坐标位置
        oval = new RectF(width / 2 - 100, width / 2 - 100, width / 2 + 100, width / 2 + 100);
    }

    //初始化数据
    private void initView() {
        //画圆的画笔
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setStyle(Paint.Style.STROKE);//设置空心圆形式
        paint.setStrokeWidth(3);//设置边框宽度

        paint2 = new Paint();
        paint2 = paint;
        //文字的画笔
        textPaint = new Paint();
        textPaint.setAntiAlias(true);
        textPaint.setDither(true);
        textPaint.setTextAlign(Paint.Align.CENTER);//设置文字居中
        textPaint.setColor(Color.BLUE);//设置字体颜色蓝色
        textPaint.setTextSize(30);//设置字体大小
    }

    //绘制图形
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(Color.GRAY);//设置画笔颜色
        //绘制一个圆并把它放在中心
        canvas.drawCircle(width / 2, width / 2, 100, paint);

        //设置弧度颜色
        paint.setColor(Color.RED);
        //绘制一个弧度代表进度,动态更新
        canvas.drawArc(oval, -90, (int) (progress * 1f / max * 360), false, paint);
        //设置显示的文本
        textPaint.setTextAlign(Paint.Align.CENTER);
        //动态更新进度的数值
        canvas.drawText((int) ((progress * 1f / max) * 100f) + "%", width / 2, width / 2, textPaint);

    }

    //模拟资源下载
    public void startToProgress() {
        new Thread() {
            @Override
            public void run() {
                super.run();
                //执行任务
                while (progress < max) {
                    progress++;
                    try {
                        sleep(200);
                    } catch (InterruptedException e) {
                    }
                    //刷新进度条
                    postInvalidate();
                }
                //任务完成后,给主线程发送一个消息
                if (onProgressCompleteListener != null) {
                    onProgressCompleteListener.onFinish();
                }
            }
        }.start();
    }

    //1.创建监听
    public interface OnProgressCompleteListener {
        void onFinish();
    }


    //2.创建接口对象
    OnProgressCompleteListener onProgressCompleteListener;

    //3. set方法,里面的参数接口对象
    public void setOnProgressCompleteListener(OnProgressCompleteListener onProgressCompleteListener) {
        this.onProgressCompleteListener = onProgressCompleteListener;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134

(二)调用类的代码

package com.lwz.myprogressbar;

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

public class MainActivity extends AppCompatActivity implements MyProgressBar.OnProgressCompleteListener {
    MyProgressBar myView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myView = (MyProgressBar) findViewById(R.id.main_apb);
        //开始任务
        myView.startToProgress();
        //给自定义的视图添加监听事件
        myView.setOnProgressCompleteListener(this);

    }

    //任务完成后显示
    @Override
    public void onFinish() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getBaseContext(), "执行完毕", Toast.LENGTH_LONG).show();
            }
        });

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

(三)Xml文件




    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

十二.Bitmap对象的操作,压缩保存和显示

程序运行后的效果:

Android自定义View使用总结_第5张图片
Android自定义View使用总结_第6张图片
第二个和第三个按钮的效果差不多,这里就不演示了。

下面是代码

(一)xml布局文件设计




    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

(二)java代码

package com.example.bitmap;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

public class MainActivity extends AppCompatActivity {
    //定义一个Bitmap对象
    Bitmap bmp;
    //定义布局内的ImageView控件对象
    ImageView iv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        iv = (ImageView) findViewById(R.id.main_iv);
        //创建一个Bitmap对象,里面啥都没有
        //200*200 = 40000 = 40b 1024
        bmp = Bitmap.createBitmap(200, 200, Bitmap.Config.RGB_565);
        iv = (ImageView) findViewById(R.id.main_iv);
        //给ImageView设置一个Bitmap对象,默认是一块黑色的区域
        iv.setImageBitmap(bmp);


    }

    /**
     * 图片的保存
     */
    public void btn1(View v) {
        //jpg没有透明度
        //获取手机内的一个图片的地址
        String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/aa.png";
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(path);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        //压缩图片并进行保存的实际操作
        bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
        //这里保存的是黑色的图形
        //这里也可以先读取一个本地或网络的图片,然后把图片转化为Bitmap的对象
        //接着进行压缩处处理再进行保存
        try {
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 从本地中读取图片,并显示在屏幕中
     */
    public void btn2(View v) {
        //需要读取权限
        String fileName = Environment.getExternalStorageDirectory().getAbsolutePath() + "/a1.jpg";
        Bitmap bmp = BitmapFactory.decodeFile(fileName);
        iv.setImageBitmap(bmp);

    }

    /**
     * 从网络中读取图片,并显示在屏幕中
     * 这里需要网络权限
     */
    public void btn3(View v) {
        //从网络
        //域名
        new Thread() {
            @Override
            public void run() {
                URL url = null;
                try {
                    //这里需要一个网络的图片的地址
                    url = new URL("http://img.mp.itc.cn/upload/20160411/f649cfdae0cd43929dedcd1e585f4a13_th.jpg");
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                }
                try {
                    //1.子线程无法刷新UI
                    //2.主线程无法请求网络
                    InputStream is = url.openStream();
                    final Bitmap bmp = BitmapFactory.decodeStream(is);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            iv.setImageBitmap(bmp);
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();


    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114

       如果Button的文本中,英文字母全部显示为大写,不管text中写的是大写还是小写,解决办法:在Button的属性里加上android:textAllCaps=”false”就行了,

       上面都是自定义View的简单使用,当然图像特效和动画的都和自定义的View有关系,另作总结。

Android动画的使用总结:
http://blog.csdn.net/wenzhi20102321/article/details/52955725
Android属性动画的示例:
http://blog.csdn.net/wenzhi20102321/article/details/52971572

 

发表评论

添加代码片

  • HTML/XML
  • objective-c
  • Ruby
  • PHP
  • C
  • C++
  • JavaScript
  • Python
  • Java
  • CSS
  • SQL
  • 其它

还能输入1000个字符

浅谈安卓自定义view(一):制作一个最最最简单的自定义view

wsyizmao wsyizmao

11-09 4734

对于安卓程序员来说,自定义view简直不要太重要,毕竟有很多功能,譬如圆形头像这些,用单纯的原生非常难以实现,而用自定义view,简直分分钟。在这里,我尝试用最简单方式跟初学者说一下如何自定义一个自己...

自定义View,有这一篇就够了

huachao1001 huachao1001

06-03 5.6万

我的简书同步发布:自定义View,有这一篇就够了 为了扫除学习中的盲点,尽可能多的覆盖Android知识的边边角角,决定对自定义View做一个稍微全面一点的使用方法总结,在内容并没有什么独特,其他大神...

Android 自定义View

chituhuan chituhuan

05-17 549

Android 自定义View一 简单的自定义ViewAndroid View 的绘制流程主要有 onMeasure, onLayout, onDraw. UI 内容的绘制主要在onDraw 中完成。...

Android自定义view之measure、layout、draw三大流程

zuguorui zuguorui

04-13 4567

自定义view之view显示流程 一个view要显示出来,需要经过测量、布局和绘制这三个过程,本章就这三个流程详细探讨一下。View的三大流程具体分析起来比较复杂,本文不会从根源详细地分析,但是可...

Android自定义View 一<最简单的自定义View>

qq_36209474 qq_36209474

03-19 3629

为什么要自定义Viewandroid提供了很多控件供我们使用 但有些功能是系统所提供的实现不 了的 这时候我们就需要自定义一个View来实现我们所需要的效果. 在Android中所有的控件都直...

Android自定义View绘制流程小结

wjw190077 wjw190077

01-24 999

总之一句话,当系统控件满足不了我们的需求时,就需要自定义View来实现,足以表达自定义有多么强大! 通过网上资料和结合自己实践,这篇文章主要用来理解绘制流程的一个具体过程的,绘制流程的起始都是在Vi...

Android自定义View实战】之你应该明白的事儿

u010785585 u010785585

10-24 3464

在Android的实际开发中,我们Android系统本身已经给我们提供了很丰富的UI以及各种实用的控件,例如TextView,Button,ImageView等。用这些基础控件已经能够实现非常优美的界...

手把手教你写一个完整的自定义View

carson_ho carson_ho

03-14 2.9万

前言 自定义View是Android开发者必须了解的基础 今天,我将手把手教你写一个自定义View,并理清自定义View所有应该的注意点 阅读本文前,请先阅读我写的一系列自定义View文章 ...

Android 自定义View (一)

lmj623565791 lmj623565791

04-21 40.4万

很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章。先总结下自定义View的步骤...

Android自定义view详解

pengpenggxp pengpenggxp

07-11 6358

对于我这样一个Android初级开发者来说,自定义View一直是一个遥不可及的东西,每次看到别人做的特别漂亮的控件,自己心里那个痒痒啊,可是又生性懒惰,自己不肯努力去看书,只能望而兴叹,每次做需求用到...

文章热词

android 运行时 闪退 android 扫描识别边框 android dot 指示器 android商品低价提醒 android返回快捷键

相关热词

android和 android】 android与 android框 android栈

自定义仪表盘控件(源码中已经改成了自己绘制表盘)

lqc1992 lqc1992

08-09 4598

新的任务又来了,这次需要实现一个仪表盘的自定义控件,自定义控件一不常写就手生,这次又巩固下,并且学了一些新知识。https://developer.android.com/training/custo...

Android自定义View的三种实现方式

luckrr luckrr

07-07 227

参考别人的文章,简明易懂,留个笔记  参考原文链接 在毕设项目中多处用到自定义控件,一直打算总结一下自定义控件的实现方式,今天就来总结一下吧。在此之前学习了郭霖大神博客上面关于自定义View的几...

自定义View Layout过程 - 最易懂的自定义View原理系列(3)

carson_ho carson_ho

02-20 1.4万

前言 自定义View是Android开发者必须了解的基础 网上有大量关于自定义View原理的文章,但存在一些问题:内容不全、思路不清晰、无源码分析、简单问题复杂化 等 今天,我将全面总结自定义V...

自定义view中onMeasure、onLayout、onDraw、onFinishInflate、onSizeChanged方法调用时机

anhenzhufeng anhenzhufeng

06-06 2409

一般自定义view或viewGroup基本上都会去实现onMeasure、onLayout、onDraw方法,还有另外两个方法是onFinishInflate和onSizeChanged。 on...

Android动态创建View

wenweidev wenweidev

09-07 1026

代码 View view = new View(context); LinearLayout.LayoutParams params = new LinearLayo...

自定义View基础 - 最易懂的自定义View原理系列(1)

carson_ho carson_ho

02-20 1.7万

前言 自定义View原理是Android开发者必须了解的基础; 在了解自定义View之前,你需要有一定的知识储备; 本文将全面解析关于自定义View中的所有知识基础。 目录1. View的分类视图Vi...

自定义View Measure过程 - 最易懂的自定义View原理系列(2)

carson_ho carson_ho

02-20 1.6万

前言 自定义View是Android开发者必须了解的基础 网上有大量关于自定义View原理的文章,但存在一些问题:内容不全、思路不清晰、无源码分析、简单问题复杂化 等 今天,我将全面总结自定义Vi...

Android自定义View注意事项

myth13141314 myth13141314

08-06 165

自定义View的分类 继承View重写onDraw方法 主要用于实现不规则的效果,即这种效果不方便通过布局的组合方式来实现。相当于就是得自己“画”了。采用这种方式需要自己支持wrap_cont...

Android自定义View-自定义组件

yilei0033 yilei0033

03-05 136

Android自定义组件 android自定义组件一般有三种实现方式: 一、组合控件:组合控件,顾名思义就是将一些小的控件组合起来形成一个新的控件,这些小的控件多是系统自带的控件。 二、自绘控件:...

Android 自定义View(一)

qq_15192113 qq_15192113

05-31 202

Android自定义View

Android自定义View入门---自定义一个TextView

jsonnan jsonnan

06-28 1290

自定义一个TextView本篇作为入门级介绍,以自定义TextView为案例,介绍一下自定义View的流程。自定义View玩的比较溜的小伙伴们可以略过。 简介 自定义View的类型 自定义View的套...

android 中的绘制类Paint 画笔,Canvas 画布,Bitmap 类和BitmapFactory及自定义属性

Dr_abandon Dr_abandon

11-23 2592

常用的绘图类是Paint 画笔,Canvas 画布,Bitmap 类和BitmapFactoryPaint类Paint类代表画笔,用来描述图形的颜色和风格,如线宽,颜色,透明度,和填充效果等信 息,...

Android自定义View的初步总结

yuminfeng728 yuminfeng728

06-08 4109

概述在开发过程中,经常会遇到系统中提供的控件无法满足产品的设计需求,这时可能就需要考虑使用自定义的View来实现产品的设计细节了。对于自定义View,可以分为两种,一种是自定义控件(继承View),另...

自定义控件玩套路以及canvas StaticLayout的使用

qq_28195645 qq_28195645

05-18 7479

自定义控件玩套路以及canvas StaticLayout的使用

Android自定义View总结(一)基础知识与实例

chen_lian_ chen_lian_

05-20 1122

Android中,View不属于四大组件,但它甚至比Receiver和Provider都要重要。 Android提供了许多基础的控件,但远远不能满足我们的需要,很多时候我们根据需求进行新控件的定义,这...

Android自定义View的用法总结

bigconvience bigconvience

05-23 4601

本文参考了:http://greenrobot.me/devpost/android-custom-layout/ Android SDK中提供了很多UI组件,如RelativeLayout, L...

下载

android 自定义View

12-13

android 自定义View android 自定义View

下载

自定义view

05-18

android自定义view,自定义属性的使用

下载

Android自定义View

03-20

Android中自定义View操作Android中自定义View操作Android中自定义View操作

Android 自定义view完全解析--带你通透了解自定义view

u011200604 u011200604

02-22 8767

参考转自郭霖博客带你一步步深入了解View系列 Android LayoutInflater原理分析 相信接触Android久一点的朋友对于LayoutInflater...

Android应用自定义View绘制方法手册

yanbober yanbober

04-04 3万

这篇迟迟难产的文章算是对2015前半年的一个交代吧,那时候有一哥们要求来一发Android Canvas相关总结,这哥们还打赏了,实在不好意思,可是这事一放就给放忘了,最近群里小伙伴催着说没更新博客,...

Android自定义View(二、深入解析自定义属性)

u010163442 u010163442

05-21 2.5万

转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51454685 本文出自:【openXu的博客】 [TOC] 在上一篇博...

简单说说Android自定义view学习推荐的方式

wingichoy wingichoy

01-08 9279

这几天比较受关注,挺开心的,嘿嘿。 这里给大家总结一下学习自定义view的一些技巧。 1.首先 去看看鸿洋神的博客 Android 自定义view(1). 鸿洋神的入门教程讲的很详细。再次膜拜...

自定义View自定义属性及引用

bobo8945510 bobo8945510

11-17 5510

学习导航….后续添加,自定义view不是一章能说清的。本章讲解: 自定义视图,我们需要做哪些准备!对于一些中级的开发者来说就要接触到自定义视图,由于Android自带的视图无法满足自己需求,又或者美观...

自定义View不能显示?来看看Studio怎么说!

github_37586705 github_37586705

10-16 942

android自定义view不显示

自定义View(三)---自定义View整个流程的梳理与总结

cjm2484836553 cjm2484836553

04-30 1280

转载请注明出处:From李诗雨—http://blog.csdn.net/cjm2484836553/article/details/71024436 不诗意的女程序猿不是好厨师~ 在自定义Vi...

Android自定义View高级(一)-分类与流程

u014005316 u014005316

01-19 1323

一.自定义View绘制流程二.自定义View分类 自定义ViewGroup 自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件,大多继承自ViewGroup或各种Layou...

Android-自定义View使用

githan githan

10-25 296

Android所有的控件都继承至View,所以我们可以通过继承View来实现自己想要的控件,具体代码如下:1,创建自定义View 类import android.content.Context; im...

Android - 自定义View不显示

u012246458 u012246458

12-06 3740

说明: 自定义了一个LinearLayout,显示不出来 原因是必须有 public ManDaoH5View(Context context, AttributeSet attrs) { 这个方法...

下载

Android自定义View之进度条Demo

10-23

Android自定义View之进度条Demo,Android自定义View之进度条Demo

自定义view-二,使用枚举

qq_15771061 qq_15771061

04-05 979

在自定义View中添加enum类型,类似android 中的match_parent和wrap_content

下载

android自定义view(一)——attire 使用

06-04

android自定义view(一)——attire 使用

Android使用handler和Runnable结合,自定义View更新UI的Demo

canghai1129 canghai1129

04-12 2449

前三周在修改android4.2锁屏UI,刚做android好多知识不会啊,里面有个动画效果是一个jian...

下载

自定义view解决android文本排版和换行问题

03-23

自定义view解决android文本排版和换行问题自定义view解决android文本排版和换行问题自定义view解决android文本排版和换行问题自定义view解决android文本排版和换行问题自定义view解决android文本排...

下载

android自定义view:十字按钮(用于智能家电APP)

12-02

本十字按钮可用于智能家电app,通过设置listener就可以监听四个方向的点击事件,同时其button的反应模式如系统给的button一致。在代码中也给出了另外五个普通按钮进行与十字按钮进行效果对比

自定义View——坑、技巧、调优

sinat_15877283 sinat_15877283

04-04 2620

相信有创建过“自定义View”经验的众多的开发者朋友当中有相当一部分人猿友是直接copy网上的一些代码拿来用,结果往往不尽如人意, 碰到bug或者是需求发生变化时往往手忙脚乱,android自定义Vi...

安卓自定义View进阶 - 贝塞尔曲线

u013831257 u013831257

04-29 1.4万

在上一篇文章Path之基本图形中我们了解了Path的基本使用方法,本次了解Path中非常非常非常重要的内容-贝塞尔曲线。...

Android自定义View的官方套路

yissan yissan

04-12 1.7万

概述Android已经为我们提供了大量的View供我们使用,但是可能有时候这些组件不能满足我们的需求,这时候就需要自定义控件了。自定义控件对于初学者总是感觉是一种复杂的技术。因为里面涉及到的知识点会比...

Android 自定义View之绘图

moira33 moira33

01-19 2074

【Android 自定义View之绘图】 Android 自定义View之绘图 基础图形的绘制 一Paint与Canvas Paint Paint的基本设置函数 setAntiAliastrue...

自定义View之基础篇

showdy showdy

12-10 579

Android APP屏幕区域划分: 1.状态栏区域: //获取屏幕区域的宽高等尺寸获取 DisplayMetrics metrics = new DisplayMetrics(); ...

没有更多推荐了,返回首页

个人资料

峥嵘life

已关注

原创

343

粉丝

617

喜欢

1035

评论

369

等级:

访问:

88万+

积分:

1万+

排名:

1874

勋章:

持之以恒

授予每个自然月内发布4篇或4篇以上原创或翻译IT博文的用户。不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累!

最新文章

  • Android 多线程之HandlerThread 详解
  • java判断一个字节数组在另一个字节数组的位置
  • 阿里巴巴的FastJson数据解析介绍
  • 讯飞语音识别和唤醒开发示例
  • 使用adb logcat命令显示Android设备上的Log日志

个人分类

  • android259篇
  • C语言基础6篇
  • java105篇
  • java集合4篇
  • java IO8篇
  • 数据库2篇
  • 人生感言13篇
  • Socket编程2篇
  • 面试13篇
  • java多线程6篇
  • Android文件资源使用11篇
  • UI42篇
  • Andr图形和动画7篇
  • Android多媒体3篇
  • 工具类13篇
  • android数据7篇
  • 消息处理机制3篇
  • 广播接收者1篇
  • 安卓服务2篇
  • Android网络25篇
  • 传感器1篇
  • 框架模式2篇
  • 插件4篇
  • 网络框架17篇
  • 高级控件13篇
  • xutils4篇
  • Fragment4篇
  • Vitamio1篇
  • 百度地图开发2篇
  • 设计模式25篇
  • ps17篇
  • webservice3篇
  • 报错情况3篇
  • dicom图像文件6篇
  • kotlin15篇

展开

归档

  • 2018年9月 3篇
  • 2018年8月 1篇
  • 2018年7月 5篇
  • 2018年6月 6篇
  • 2018年5月 5篇
  • 2018年4月 15篇
  • 2018年3月 12篇
  • 2018年2月 7篇
  • 2018年1月 1篇
  • 2017年12月 3篇
  • 2017年11月 7篇
  • 2017年10月 8篇
  • 2017年9月 7篇
  • 2017年8月 5篇
  • 2017年7月 20篇
  • 2017年6月 10篇
  • 2017年5月 14篇
  • 2017年4月 15篇
  • 2017年3月 23篇
  • 2017年2月 22篇
  • 2017年1月 9篇
  • 2016年12月 45篇
  • 2016年11月 26篇
  • 2016年10月 21篇
  • 2016年9月 45篇
  • 2016年8月 16篇

展开

热门文章

  • javaj经典程序编程50题

    阅读量:48214

  • java多线程的常见例子

    阅读量:32260

  • eclipse快捷键的设置和使用

    阅读量:30320

  • Android显示时间和日期的控件的使用总结

    阅读量:22081

  • Java IO流经典练习题

    阅读量:21601

最新评论

  • Android 多线程之Handl...

    headw:写的这是什么玩意。。。。。

  • Android一次申请多个动态权限

    weixin_39657438:转载了 楼主写的很清晰

  • 使用cmd根据WSDL网址生成ja...

    qq_41913924:[reply]Daisy_ljq[/reply] 在你发布webService的时候设置

  • Android网络定位或GPS定位

    weixin_40413165:大神,我按照您的程序写出,无法获取经纬度信息啊,就是什么都不显示,请教请教

  • 走穿java23种设计模式-3抽象...

    MirabelleZWH:谢谢分享

联系我们

客服

请扫描二维码联系客服

[email protected]

400-660-0108

QQ客服 客服论坛

关于招聘广告服务 网站地图

©2018 CSDN版权所有 京ICP证09002463号

百度提供搜索支持

经营性网站备案信息

网络110报警服务

中国互联网举报中心

北京互联网违法和不良信息举报中心

CSDN APP

  • 点赞取消点赞

    5

  • 评论

     

  • 目录
    1. 一View 的基本概念
      1. 一View的理解
      2. 二IDs
      3. 三获取View的位置信息
    2. 二View创建概述
      1. 一Creation创建流程
        1. 调用构造器
      2. 二Layout布局流程
        1. onMeasureint w int h 确定View和它所有的子View要求的尺寸时调用
        2. onLayoutboolean change int left int topint right int button 当这个View为其所有的子View指派一个尺寸和位置时调用
        3. onSizeChangedint w int h int oldw int oldh 当这个View的尺寸改变后调用
      3. 四Drawing绘制过程自定义View的重点方法哦
      4. 五Event事件流程
        1. onKeyDownint KeyEvent当一个新的键按下时
        2. onKeyUpint KeyEvent 当一个键弹起时
        3. onTrackballEventMotionEvent当滚迹球事件发生时
        4. onTouchEventMotionEvent当一个触摸屏事件发生时
      5. 五Focus焦点流程
        1. onFocusChangedboolean intRect 当View得到和失去焦点时调用
        2. onWindowFocusChangedboolean 当Window包含的View得到或失去焦点时调用
    3. 三定制View
      1. 一扩展View或者View的子类
      2. 二 必须实现其中一个构造方法一般都是实现两个
      3. 三重写onDrawcanvas方法进行绘制整个涉及到绘制任意的图像比如画线画圆画矩形等等
      4. 四如需调整大小重写onMesure默认是全屏的
      5. 五如需样式在xml中布置自定义属性
    4. 四测量布局MeasureSpec
      1. 一下面是各个模式的标志位表示
      2. 二这样表示一个View大小是很方便的我们来看下面的方法
        1. 下面是网友对MeasureSpec的一个理解
    5. 五常用的绘图类
      1. 一Paint类
        1. 常用方法paint
      2. 二Bitmap类
        1. compressBitmapCompressFormat format int quality OutputStream stream
        2. createBitmapBitmap source int x int y int width int height Matrix m boolean filter
        3. createBitmapBitmap source int x int y int width int height
      3. 三BitmapFactory类
        1. decodeFileString pathName 用于从给定的路径所指定的文件中解析创建Bitmap对象
      4. 四Canvas类
      5. 绘制几何图形
        1. 绘制文本
        2. 绘制路径
    6. 六自定义属性这个使用起来相对比较麻烦一般不用
      1. 一attsxml的文件
      2. 二自定义属性格式和意义
      3. 三在布局文件中使用自定义属性
      4. 四然后我们在自定义View中实现带AttributeSet属性的构造方法并且获取自定义值
    7. 七组合控件
      1. 一创建文件title_textxml
      2. 二接下来创建一个TitleView继承自FrameLayout代码如下所示
    8. 八绘制图片返回的都是一个Bitmap对象
      1. 一drawBitmapBitmap bitmap Rect src RectF dst Paint paint
      2. 二drawBitmapBitmap bitmap float left float top Paint paint
      3. 三drawBitmapBitmap bitmap Rect src Rect dst Paint paint
    9. 下面是一些程序的示例
    10. 九一个绘制简单图形图像的示例
      1. 一创建MyView继承View
      2. 二调用
    11. 十简易画板的实现
    12. 十一一个自定义的进度框框的显示
      1. 一自定义View的代码
      2. 二调用类的代码
      3. 三Xml文件
    13. 十二Bitmap对象的操作压缩保存和显示
      1. 一xml布局文件设计
      2. 二java代码

     

  • 收藏
  • 手机看
  • 上一篇
  • 下一篇
  • 更多
    • 上一篇
    • 下一篇

 

 

不良信息举报

 

举报内容:

Android自定义View使用总结

举报原因:

色情政治抄袭广告招聘骂人其他

原文地址:

 

原因补充:

最多只允许输入30个字

 

  •  
  •  

  • 写博客
  • 发Chat
  • 传资源
  • 登录注册
  • 个人中心

    我的博客

    消息(3)

    创作中心

    帐号设置

    我的C币

    订单中心

    帮助

    退出

  • 简单说说Android自定义view学习推荐的方式

    01-08 9279
  • 自定义View—自定义属性及引用

    11-17 5510
  • 自定义View不能显示?来看看Studio怎么说!

    10-16 942
  • 自定义View(三)---自定义View整个流程的梳理与总结

    04-30 1280
  • Android自定义View高级(一)-分类与流程

    01-19 1323
  • Android-自定义View的使用

    10-25 296
  • Android - 自定义View不显示

    12-06 3740
  • 下载

    Android自定义View之进度条Demo

    10-23
  • 自定义view-二,使用枚举

    04-05 979
  • 下载

    android自定义view(一)——attire 使用

    06-04
  • Android使用handler和Runnable结合,自定义View更新UI的Demo

    04-12 2449
  • 下载

    自定义view解决android文本排版和换行问题

    03-23
  • 下载

    android自定义view:十字按钮(用于智能家电APP)

    12-02
  • 自定义View——坑、技巧、调优

    04-04 2620
  • 安卓自定义View进阶 - 贝塞尔曲线

    04-29 1.4万
  • Android自定义View的官方套路

    04-12 1.7万

Android自定义View使用总结

2016年11月29日 16:49:19 峥嵘life 阅读数:3148 标签: android widget 自定义View 更多

个人分类: Andr图形和动画 android

版权声明:本文为博主原创文章。只要评论中留言就可以转载。 https://blog.csdn.net/wenzhi20102321/article/details/53395111

      很多人把自定义View想象得很复杂,其实一步一步的去理解记忆,它的知识点并不是很难,但是它的应用方向确实是比较多。本文先简单的介绍一下自定义View和它的使用。

一.View 的基本概念

(一)View的理解

       View是一个Android视图的基础类,这个类是用户接口的基础构件。 View 表示屏幕上的一块矩形区域,负责绘制这个区域和事件处理。 View 是所有widget类的基类,Widget 类用于创建交互式UI构件(按钮,输入框等)。 View 类的ViewGroup子类是layout的基类,Layout是一个不可见的容器,它保存着 View(或ViewGroup)并定义这些View的layout属性。 可以说View类是用户视图接口类中最重要的一个类,就像Object类是所有类的基础父类相似,不过View是针对的是视图。

(二)IDs:

        Views 有一个整数相对应,id被用于在View树中找到指定的View。可以在layout文件中 定义 一个唯一的ID, 在Activity的onCreate函数中调用findViewById来查找这个View。 在整个树内,id可以不是唯一的,但再指定的范围内查找时我们可以确信它是唯一的。比如不同的xml布局文件中可以存在相同id编号,但是同一个xml布局文件中不能存在相同的id编号。

(三)获取View的位置信息

View是一个矩形区域, 使用左&上的坐标以及长和宽可以表示一个View。我们可以使用方 法getLeft() , getTop(),getRight(),getBottom(),getWidth(),getHeight()等函数来获取其位置信息.

二.View创建概述

在API中对View的回调流程有以个详细的描述:

(一)Creation:创建流程

1.调用构造器

public View(Context context) //使用java代码创建View时的构造方法
public View(Context context, AttributeSet attrs)//在XML中配置时的构造 方法,attrs存储xml中设置的属性
上面这两个构造方法都是要重写的,哪怕只是使用其中一个。并且初始化数据在这两个构造方法都要做一遍。
2.onFinishInflate() //当View和他的所有子View从XML中解析完成后调用。 一般不怎么用!

(二)Layout:布局流程

1.onMeasure(int w, int h) //确定View和它所有的子View要求的尺寸时调用

2.onLayout(boolean change, int left, int top,int right, int button) //当这个View为其所有的子View指派一个尺寸和位置时调用

3.onSizeChanged(int w, int h, int oldw, int oldh) //当这个View的尺寸改变后调用

(四)Drawing:绘制过程(自定义View的重点方法哦)

onDraw(Canvas) //当View给定其内容时调用

(五)Event:事件流程

1.onKeyDown(int, KeyEvent)//当一个新的键按下时

2.onKeyUp(int, KeyEvent) //当一个键弹起时

3.onTrackballEvent(MotionEvent)//当滚迹球事件发生时

4.onTouchEvent(MotionEvent)//当一个触摸屏事件发生时

(五)Focus:焦点流程

1.onFocusChanged(boolean, int,Rect) //当View得到和失去焦点时调用

2.onWindowFocusChanged(boolean) //当Window包含的View得到或失去焦点时调用。

三.定制View

      为了实现一个定制View, 需要重写一些View的标准方法。 framework会调用这些方法, 并且认为这些方法应该是所有的view都有实现。 这些方法不必全部重写。
      事实上,可以只重写onDraw方法就可以了自定义View的步骤:

(一)扩展View或者View的子类。

例如:
class MyView extends View
class MyView extends TextView
class MyView extends LinearLayout
class MyView extends ViewPager
  • 1
  • 2
  • 3
  • 4
  • 5

      这些都是自定义View的扩展,比如继承了TextView可以直接使用它的方法,setText(“xxx”);setBackColor(0xf00);等等。

(二) 必须实现其中一个构造方法,一般都是实现两个。

(三)重写onDraw(canvas)方法进行绘制,整个涉及到绘制任意的图像,比如画线,画圆,画矩形等等。

(四)如需调整大小,重写onMesure,默认是全屏的。

(五)如需样式在xml中布置,自定义属性。

这相当于静态使用View,比如

  • 1
  • 2
  • 3
  • 4
  • 5

      这里在静态布局中看不出什么设置,但是在MyView中可以做很多设置,比如设置好里面的文本字体、背景、甚至里面对应控件的点击事件都是可以预先在MyView中设置好的。

四.测量布局MeasureSpec

      在View系统中,指定宽和高,以及指定布局的属性,是由MeasureSpec来封装的。

(一)下面是各个模式的标志位表示。

1.private static final int MODE_SHIFT = 30;   
2.private static final int MODE_MASK  = 0x3 << MODE_SHIFT;   
3.public static final int UNSPECIFIED = 0 << MODE_SHIFT; 
4.public static final int EXACTLY     = 1 << MODE_SHIFT;
5.public static final int AT_MOST     = 2 << MODE_SHIFT;  
  • 1
  • 2
  • 3
  • 4
  • 5

      在这个解析系统中是通过移位来存放更多的数据,现在每个数据标志位都向左移动了30位。

(二)这样表示一个View大小是很方便的,我们来看下面的方法:

1.public static int makeMeasureSpec(int size, int mode) { 
  return size + mode;  
 }  
  • 1
  • 2
  • 3

      通过这个方法就可以制作一个含有两个参数的int值,这个参数包含一个mode标志和一个宽或高的表示。

2.public static int getMode(int measureSpec) {   
    return (measureSpec & MODE_MASK);    
     }  
  • 1
  • 2
  • 3

      通过方法来获取到mode。

3. public static int getSize(int measureSpec) {  
           return (measureSpec & ~MODE_MASK);    
}  
  • 1
  • 2
  • 3

      用方法来获取高或宽的数据。

      测量这个View的高和宽。通过调用这个方法来设置View的测量后的高和宽,其最终调用的方 法是:

4.protected final void setMeasuredDimension(int measuredWidth, in t measuredHeight) { 
 mMeasuredWidth = measuredWidth; 
 mMeasuredHeight = measuredHeight;  
 mPrivateFlags |= MEASURED_DIMENSION_SET;    
       }  
  • 1
  • 2
  • 3
  • 4
  • 5

      可见其最终是将高和宽保存在mMeasuredWidth、mMeasuredHeight这两个参数中。

下面是网友对MeasureSpec的一个理解:

在自定义View和ViewGroup的时候,我们经常会遇到int型的MeasureSpec来表示一个组件的大小,这个变量里面不仅有组件的尺寸大小,还有大小的模式。

这个大小的模式,有点难以理解。在系统中组件的大小模式有三种:

1.精确模式
在这种模式下,尺寸的值是多少,那么这个组件的长或宽就是多少。

2.最大模式
这个也就是父组件,能够给出的最大的空间,当前组件的长或宽最大只能为这么大,当然也可以比这个小。

3.未指定模式
这个就是说,当前组件,可以随便用空间,不受限制。

可能有很多人想不通,一个int型整数怎么可以表示两个东西(大小模式和大小的值),
一个int类型我们知道有32位。而模式有三种,要表示三种状态,至少得2位二进制位。
于是系统采用了最高的2位表示模式:

最高两位是00的时候表示"未指定模式"。即MeasureSpec.UNSPECIFIED
最高两位是01的时候表示"'精确模式"。即MeasureSpec.EXACTLY
最高两位是11的时候表示"最大模式"。即MeasureSpec.AT_MOST


很多人一遇到位操作头就大了,为了操作简便,于是系统给我提供了一个MeasureSpec工具类。
这个工具类有四个方法和三个常量(上面所示)供我们使用:


//这个是由我们给出的尺寸大小和模式生成一个包含这两个信息的int变量,这里这个模式这个参数,传三个常量中的一个。
public static int makeMeasureSpec(int size, int mode)


//这个是得到这个变量中表示的模式信息,将得到的值与三个常量进行比较。
public static int getMode(int measureSpec)


//这个是得到这个变量中表示的尺寸大小的值。
public static int getSize(int measureSpec)


//把这个变量里面的模式和大小组成字符串返回来,方便打日志
 public static String toString(int measureSpec)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

五.常用的绘图类

      常用的绘图类是Paint 画笔,Canvas 画布,Bitmap 类和BitmapFactory。

(一)Paint类

      Paint类代表画笔,用来描述图形的颜色和风格,如线宽,颜色,透明度,和填充效果等信息,使用Paint时,需要先创建该类的对象,这可以通过该类提供的构造方法来实现。通常情况下,只需要使用无参数的构造方法来创建一个使用默认设置的Paint对象:

Panit paint=new Panint();

常用方法paint.:

  1. setARGB(int a, int r, int g, int b) 用于设置颜色,各参数值均为0~255之间的整数,分别用于表示透明度、红色、绿色和蓝色值
  2. setColor(int color) 用于设置颜色,参数color可以通过Color类提供的颜色常量指定
    3.Color.rgb(in t red,int green,int blue)方法指定颜色
  3. setAlpha(int a) 用于设置透明度,值为0~255之间的整数
  4. setAntiAlias(boolean aa) 用于指定是否使用抗锯齿功能,如果使用会使绘图速度变慢 ,但是一般图像绘制都会设置使用。
    6.setDither(boolean dither) 用于指定是否使用图像抖动处理,如果使用会使图像颜色更加平滑和饱满,更加清晰
  5. setShader(Shader shader) 用于设置渐变,可以使用LinearGradient(线性渐变)、RadialGradient(径向渐变)或 者SweepGradient(角度渐变),后面分别做详细介绍 8.setStrokeWidth(float width) 用于设置笔触的宽度 9. setStyle(Paint.Style style) 用于设置填充风格,参数值 为Style.FILL表示实心、Style.FILL_AND_STROKEStyle.STROKE表示空心 10.setTextAlign(Paint.Align align) 用于设置绘制文本时的文字对齐方式,参数值为Align.CENTERAlign.LEFTAlign.RIGHT
  6. setTextSize(float textSize) 用于设置绘制文本时的文字的大小

12.渐变的几种表示形式
(1)线性渐变
new LinearGradient(0, 0, 50, 50, Color.RED, Color.GREEN, Shader.TileMod e.MIRROR);
参数一为渐变起初点坐标x位置
参数二为y轴位置
参数三和四分别对应渐变终点
最后参数为平铺方式,这里设置为镜像

(2)径向渐变
new RadialGradient(160, 110, 50, Color.RED, Color.GREEN, Shader.TileMod e.MIRROR);
参数一,参数二为渐变圆中心坐标
参数三为半径
参数四,参数五
参数六为平铺方式

(3)角度渐变
new SweepGradient(265, 110, new int[] { Color.RED, Color.GREEN, Color.B LUE }, null);
参数一参数二为渲染中心点x,y坐标
参数三为围绕中心渲染的颜色数组,至少要有两种颜色值
参数四为相对位置的颜色数组,若为null,颜色沿渐变线均匀分布

(二)Bitmap类

      Bitmap类代表位图,它是Android系统中图像处理的最重要类之一,使用它不仅可以获取图像文件信息,进行图像剪切,旋转,缩放等操作,而且还可以指定格式保存图像文件。 Bitmap类常用的方法

1. compress(Bitmap.CompressFormat format, int quality, OutputStream stream)

用于将Bitmap对象压缩为指定格式并保存到指定的文件输出流中,简单的说就是能保存一个图片到本地。
参数一:数值可以是Bitmap.CompressFormat.PNG、Bitmap.CompressFormat. JPEG和Bitmap.Compres sFormat.WEBP
参数二:0到100,100为最大品质值,
参数三:输出流,可以是文件输出流输出保存到本地,可以是网络输出流对应的就会输出到网络中。

2.createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)

用于从源位图的指定坐标点开始,“挖取”指定宽度和高度的一块图像来创建新的Bitmap对象,并按Matrix指定规则进行变换
参数一:要被挖取的Bitmap对象
参数二三:开始挖的左边和上边的位置
参数四五:要挖宽度和高度。
参数六:一个枚举类型的配置,可以定义截到的新位图的质量

最后一个参数:filter解释:
true if the source should be filtered. Only applies if the matrix contains more than just translation.
当进行的不只是平移变换时,filter参数为true可以进行滤波处理,有助于改善新图像质量;flase时,计算机不做过滤处理。
要想imageView.setImageMatrix()方法起作用,xml得配置android:scaleType="matrix"
matrix.setRotate和matrix.postRotate的区别:
post...:平移、旋转等效果可以叠加在一起;
set...:前一种效果会消失,只有后来的操作,即它会重置Matrix
3.createBitmap(int width, int height, Bitmap.Config config) 
用于创建一个指定宽度和高度的新的Bitmap对象
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

4.createBitmap(Bitmap source, int x, int y, int width, int height)

      用于从源位图的指定坐标点开始,“挖取”指定宽度、和高度的一块图像来创建新的Bitmap对象
5.createBitmap(int[] colors, int width, int height, Bitmap.Config config)
使用颜色数组创建一个指定宽度和高度的新Bitimap对象,其中,数组元素的个数为width*height
6.createBitmap(Bitmap src) 用于使用源位图创建一个新的Bitmap对象
7. createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)用于将源位图缩放为指定宽度和高度的新的Bitmap对象
8.isRecycled() 用于判断Bitmap对象是否被回收 9.recycle() 强制回收Bitmap对象

(三)BitmapFactory类

      该类为一个工具类,用于从不同的数据源来解析,创建BitMap对象。

1.decodeFile(String pathName) 用于从给定的路径所指定的文件中解析、创建Bitmap对象

2.decodeResource(Resources res, int id) 用于根据给定的资源ID从指定的资源中解析、创建 Bitmap对象 3.decodeStream(InputStream is) 用于从指定的输入流中解析、创建Bitmap对象

      思 考 : 如 何 从 S D 卡 中 解 析 图 片 文 档 并 显 示 到 G r i d V i e w 中
String path = Environment.getExternalStorageDirectory() + “/”; 得到sdcard路径

(四)Canvas类

      通过该类提供的方法,可以绘制各种图形,如,矩形,圆形,和线条等,通常情况下,要在 Andaroid中绘图,需要先创建一个继承自View类的视图,并且在该类中重写它的 onDraw(Canvas canvas)方法,然后在显示绘图的Activity中添加该视图。

1.绘制几何图形

Android提供了强大的二维图形库,比较常用的是绘制几何图形,绘制文本,路径和图片等 比较常见的图形包括点,线,弧,圆形,矩形,在Android中,Canvas类提供了丰富的绘制几何图形的 方法,通过这些方法可以绘制出各种几何图形,常用的绘制几何图形的方法如下:

  1)填充
      drawARGB(int a, int r, int g, int b)
      drawColor(int color)
      drawRGB(int r, int g, int b)
      drawColor(int color, PorterDuff.Mode mode)
  2)几何图形
     canvas.drawArc (扇形)
     canvas.drawCircle(圆)
     canvas.drawOval(椭圆)
     canvas.drawLine(线)
     canvas.drawPoint(点)
     canvas.drawRect(矩形)
     canvas.drawRoundRect(圆角矩形)
     canvas.drawVertices(顶点)
     cnavas.drawPath(路径)
   3)图片
       canvas.drawBitmap (位图)
       canvas.drawPicture (图片)
   4)文本
       canvas.drawText
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

2.绘制文本

      在Android中,可以通过TextView来显示文本,但是,在开发游戏时,特别是开发RPG类游戏时,会包含很多文字 ,使用TextView和图片显示文本不太合适,这时,就需要通过绘制文本的方式来实 现,Canvas类提供了一系列的绘制文本的方法,

(1) drawText(String text,float x,float y, Paint paint)

参数分别是,要绘制的文本,文字的起始位置X坐标,文字起始位置的Y坐标

(2) drawPosText(String text,float[] pos Paint paint)

参数分别是,要绘制的文本,每个字符的位置,该方法已过期.

(3)文字对齐使用Paint的TextAlign(xxx);

3.绘制路径

      在Android中,提供了绘制路径的功能,绘制一条路径可以分为创建路径和绘制定义好的路径两部分创建路径: 使用android.graphics.Path类来实现,Path类包含一组矢量绘图方法,如,画圆,矩形,弧,线条 等,常用的方法如下
(1) addArc(RectF oval, float startAngle, float sweepAngle) 添加弧形的路径
(2)addCircle(float x, float y, float radius, Path.Direction dir) 添加圆形的路径 //Path.Direction类型的常量,可选值为Path.Direction.CW(顺时针)和Path.Directio n.CCW(逆时针).下面同。
(3) addOval(RectF oval, Path.Direction dir) 添加椭圆形路径
(4) addRect(RectF rect, Path.Direction dir) 12. 添加矩形路径
(5)addRoundRect(RectF rect, float rx, float ry, Path.Direction dir) 添加圆角矩形路径
(6)moveTo(float x, float y) 设置开始绘制直线的起始点
(7)lineTo(float x, float y) 在moveTo()方法设置的起始点与该方法指定的结束点之间画一条直线,如果在调用该方法之前没使用moveTo()方法设置起始点,那么将从(0,0)点开始绘制直线
(8)quadTo(float x1, float y1, float x2, float y2)
用于根据指定的的参数绘制一条线段轨迹
(9)close() 闭合路径

六.自定义属性,这个使用起来相对比较麻烦,一般不用

我们在XML布局下经常使用的id,layout_width,layout_height等等参数,那么我们如何定义自 己的属性呢?

(一)atts.xml的文件


  

     
 

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

(二)自定义属性格式和意义

1. reference       引用 
2. color           颜色 
3. boolean         布尔值 
4. dimension       尺寸值 
5. float           浮点值 
6. integer         整型值 
7. string          字符串 
8. enum            枚举值
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

(三)在布局文件中使用自定义属性

  
android:layout_height="wrap_content"
app:textColor="#f00" 
app:textSize="20dp" /> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

(四)然后我们在自定义View中实现带AttributeSet属性的构造方法,并且获取自定义值

public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
 //将属性数组提取出来 
 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.M yView); 
//获取对应的自定义属性,并且给默认值
 int textColor = a.getColor(R.styleable.MyView_textColor, 8.                 0X000000); 
 float textSize = a.getDimension(R.styleable.MyView_textSize, 36); 
//将值设置给画笔,绘画后颜色和大小就已经改变成我们自定义属性的值 
 mPaint.setTextSize(textSize); 
mPaint.setColor(textColor); 
//释放 
 ta.recycle();
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

      在执行完之后,一定要确保调用recycle() 方法。用于检索从这个结构对应于给定的属性位置 到obtainStyledAttributes中的值。

七.组合控件

      组合控件的意思就是,我们并不需要自己去绘制视图上显示的内容,而只是用系统原生的控件就好了,但我们可以将几个系统原生的控件组合到一起,这样创建出的控件就被称为组合控件。
      举个例子来说,标题栏就是个很常见的组合控件,很多界面的头部都会放置一个标题栏,标题 栏上会有个返回按钮和标题,点击按钮后就可以返回到上一个界面。
那么下面我们就来尝试去 实现这样一个标题栏控件。

(一)创建文件title_text.xml

  

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

      在这个布局文件中,我们首先定义了一个RelativeLayout作为背景布局,然后在这个布局里定 义了一个Button和一个TextView,Button就是标题栏中的返回按钮,TextView就是标题栏中 的显示的文字。

(二)接下来创建一个TitleView继承自FrameLayout,代码如下所示:

public class TitleView extends FrameLayout { 
private Button leftButton; 
private TextView titleText;  
public TitleView(Context context, AttributeSet attrs) { 
        super(context, attrs); 
//加载布局,并加入当前视图 
LayoutInflater.from(context).inflate(R.layout.title, this); 
titleText = (TextView) findViewById(R.id.title_text); 
leftButton = (Button) findViewById(R.id.button_left); 
leftButton.setOnClickListener(new OnClickListener() {
             @Override  
public void onClick(View v) { 
((Activity) getContext()).finish(); 
 }  
 });  
 } 
public void setTitleText(String text) { 
titleText.setText(text);
}  
public void setLeftButtonText(String text) { 
        leftButton.setText(text);  
    } 
    public void setLeftButtonListener(OnClickListener l) { 
       leftButton.setOnClickListener(l); 
    } 
 }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

      其中这个组合控件相对来说是比较灵活的,上面的标题和返回的文本都是可以替换的,并且返回的点击的监听事件是可以重写的。

八.绘制图片,返回的都是一个Bitmap对象

(一)drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)

用于从指定点绘制从源位图中“挖取”的一块拉伸

(二)drawBitmap(Bitmap bitmap, float left, float top, Paint paint)

用于在指定点绘制位图

(三)drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)

用于从指定点绘制从源位图中“挖取”的一块

下面是一些程序的示例…

九.一个绘制简单图形图像的示例

绘制效果:
Android自定义View使用总结_第7张图片
这里只是做各种图像绘制的展示。具体代码:

(一)创建MyView继承View

package com.example.myview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.view.View;

/**
 * 创建自定义View并使用其中的简单方法
 */

public class MyView extends View {
    public MyView(Context context) {
        super(context);
        initView();
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }



    //创建画笔
    Paint paint = new Paint();
    //设置一个圆心的点
    Point point = new Point();

    //初始化数据
    void initView() {
        //对画笔的基本设置
        //设置抗锯齿
        paint.setAntiAlias(true);
        //设置防抖动
        paint.setDither(true);
        //设置颜色
        paint.setColor(Color.RED);
        //设置透明的
        paint.setAlpha(128);
        //设置线条粗细
        paint.setStrokeWidth(10);
        point.set(getResources().getDisplayMetrics().widthPixels / 2, getResources().getDisplayMetrics().heightPixels / 2);

    }

    //View的视图绘制的回调方法
    //使用的是参数里面的canvas画板对象来进行各项操作
    RectF rectF = new RectF(10, 200, 400, 400);
    RectF rectF2 = new RectF(10, 650, 400, 800);

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制一条直线
        canvas.drawLine(10, 10, 100, 10, paint);
        //绘制多条直线
        canvas.drawLines(new float[]{10, 30, 200, 30, 10, 50, 300, 50,}, paint);
        //绘制一个实心圆(默认情况)
        canvas.drawCircle(point.x, point.y, 50, paint);
        //绘制一个点,这里的点是正方形的
        canvas.drawPoint(10, 300, paint);
        //绘制一个椭圆,参数直接写里面的一个方法对API等级有限制
        canvas.drawOval(rectF, paint);
        //绘制一个矩形
        canvas.drawRect(10, 400, 100, 600, paint);
        //绘制圆角矩形
        canvas.drawRoundRect(rectF2, 50, 50, paint);
        //绘制文本
        canvas.drawText("你好世界小姐", 0, paint.getTextSize(), paint);
        canvas.drawText("你好中心小姐", point.x, point.y, paint);
        //对画笔的其他设置
        paint.setTextSize(30);
        paint.setTextAlign(Paint.Align.CENTER);
        canvas.drawText("你好正中心小姐", point.x, point.y, paint);
        //画一个空心圆也设置画笔
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(point.x, point.y + 200, 50, paint);
        //设置画笔的渐变效果
        //线性渐变
        //  paint.setShader(new LinearGradient(10,650,200,800,Color.RED,Color.BLUE, Shader.TileMode.MIRROR));
        //径向渐变,像一个圆从圆点向四周扩散
        // paint.setShader(new RadialGradient(point.x,point.y,100,Color.BLACK,Color.YELLOW, Shader.TileMode.REPEAT));
        //角度渐变
        paint.setShader(new SweepGradient(100, 100, new int[]{Color.BLUE, Color.GREEN,Color.RED}, null));

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93

(二)调用

方法1:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

方法2:

(1)java代码

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

(2)xml文件代码:




    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

      其中使用第一个方法,整个页面都是MyView的显示,使用第二个调用方法,可以在xml布局文件内添加其他的控件。

十.简易画板的实现

      程序实现在页面上显示一个跟随手指移动的小球,并且随着小球的移动,留下绘制的路线。
效果如图所示:
Android自定义View使用总结_第8张图片
程序设计的代码:

package com.lwz.path;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * 使用小圆绘制图像
 */

public class TouchView extends View {
    public TouchView(Context context) {
        super(context);
        initView();
    }

    public TouchView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    //定义画笔
    Paint paint;
    //定义一个圆点
    PointF pointf;

    //定义路径
    Path path;

    //初始化数据
    private void initView() {
        paint = new Paint();
        paint.setDither(true);
        paint.setAntiAlias(true);
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        pointf = new PointF();

        path = new Path();
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        //绘制图像,这里绘制无数个圆点组成图像
       canvas.drawCircle(pointf.x, pointf.y, 10, paint);
        canvas.drawPath(path,paint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x=event.getX();
        float y=event.getY();

        if (event.getAction() == MotionEvent.ACTION_DOWN){
            path.moveTo(x,y);
        }
        //移动就绘制图像
        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            //设置点的坐标//这个重新绘制很重要
            pointf.set(event.getX(), event.getY());
            //绘制路径
            path.lineTo(x,y);
        }
        invalidate();

        return true;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

调用类的方法:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(new TouchView(this));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

十一.一个自定义的进度框框的显示

程序效果:
Android自定义View使用总结_第9张图片

      这里设计两个空心圆,一个圆是直接绘制好的,另一个是随着进度而进行绘制,。
这里还使用画笔绘制文字,也是随着进度而改变。

进度执行完成后的显示效果:
Android自定义View使用总结_第10张图片
程序设计的代码:

(一)自定义View的代码

package com.lwz.myprogressbar;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

/**
 * 绘制一个自定义的进度条的显示
 */

public class MyProgressBar extends View {
    public MyProgressBar(Context context) {
        super(context);
        initView();
    }

    public MyProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        //获取布局文件内的自定义属性
       /*  TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ArcProgressBar);
        //取出我们的属性
        max = a.getInt(R.styleable.ArcProgressBar_max, 100);
        progress = a.getInt(R.styleable.ArcProgressBar_progress, 0);
        //一定要释放
        a.recycle();*/

        initView();
    }

    //定义画笔
    Paint paint;
    Paint paint2;
    Paint textPaint;
    //最大的进度值
    private int max = 100;
    //当前的进度值
    private int progress = 0;
    //定义圆的中心点的x轴坐标
    int width;

    //定义圆点的坐标
    RectF oval;

    //测量布局时的回调方法
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取宽度
        width = getWidth();
        //确定圆的坐标位置
        oval = new RectF(width / 2 - 100, width / 2 - 100, width / 2 + 100, width / 2 + 100);
    }

    //初始化数据
    private void initView() {
        //画圆的画笔
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setStyle(Paint.Style.STROKE);//设置空心圆形式
        paint.setStrokeWidth(3);//设置边框宽度

        paint2 = new Paint();
        paint2 = paint;
        //文字的画笔
        textPaint = new Paint();
        textPaint.setAntiAlias(true);
        textPaint.setDither(true);
        textPaint.setTextAlign(Paint.Align.CENTER);//设置文字居中
        textPaint.setColor(Color.BLUE);//设置字体颜色蓝色
        textPaint.setTextSize(30);//设置字体大小
    }

    //绘制图形
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(Color.GRAY);//设置画笔颜色
        //绘制一个圆并把它放在中心
        canvas.drawCircle(width / 2, width / 2, 100, paint);

        //设置弧度颜色
        paint.setColor(Color.RED);
        //绘制一个弧度代表进度,动态更新
        canvas.drawArc(oval, -90, (int) (progress * 1f / max * 360), false, paint);
        //设置显示的文本
        textPaint.setTextAlign(Paint.Align.CENTER);
        //动态更新进度的数值
        canvas.drawText((int) ((progress * 1f / max) * 100f) + "%", width / 2, width / 2, textPaint);

    }

    //模拟资源下载
    public void startToProgress() {
        new Thread() {
            @Override
            public void run() {
                super.run();
                //执行任务
                while (progress < max) {
                    progress++;
                    try {
                        sleep(200);
                    } catch (InterruptedException e) {
                    }
                    //刷新进度条
                    postInvalidate();
                }
                //任务完成后,给主线程发送一个消息
                if (onProgressCompleteListener != null) {
                    onProgressCompleteListener.onFinish();
                }
            }
        }.start();
    }

    //1.创建监听
    public interface OnProgressCompleteListener {
        void onFinish();
    }


    //2.创建接口对象
    OnProgressCompleteListener onProgressCompleteListener;

    //3. set方法,里面的参数接口对象
    public void setOnProgressCompleteListener(OnProgressCompleteListener onProgressCompleteListener) {
        this.onProgressCompleteListener = onProgressCompleteListener;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134

(二)调用类的代码

package com.lwz.myprogressbar;

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

public class MainActivity extends AppCompatActivity implements MyProgressBar.OnProgressCompleteListener {
    MyProgressBar myView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myView = (MyProgressBar) findViewById(R.id.main_apb);
        //开始任务
        myView.startToProgress();
        //给自定义的视图添加监听事件
        myView.setOnProgressCompleteListener(this);

    }

    //任务完成后显示
    @Override
    public void onFinish() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getBaseContext(), "执行完毕", Toast.LENGTH_LONG).show();
            }
        });

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

(三)Xml文件




    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

十二.Bitmap对象的操作,压缩保存和显示

程序运行后的效果:

Android自定义View使用总结_第11张图片
Android自定义View使用总结_第12张图片
第二个和第三个按钮的效果差不多,这里就不演示了。

下面是代码

(一)xml布局文件设计




    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

(二)java代码

package com.example.bitmap;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

public class MainActivity extends AppCompatActivity {
    //定义一个Bitmap对象
    Bitmap bmp;
    //定义布局内的ImageView控件对象
    ImageView iv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        iv = (ImageView) findViewById(R.id.main_iv);
        //创建一个Bitmap对象,里面啥都没有
        //200*200 = 40000 = 40b 1024
        bmp = Bitmap.createBitmap(200, 200, Bitmap.Config.RGB_565);
        iv = (ImageView) findViewById(R.id.main_iv);
        //给ImageView设置一个Bitmap对象,默认是一块黑色的区域
        iv.setImageBitmap(bmp);


    }

    /**
     * 图片的保存
     */
    public void btn1(View v) {
        //jpg没有透明度
        //获取手机内的一个图片的地址
        String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/aa.png";
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(path);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        //压缩图片并进行保存的实际操作
        bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
        //这里保存的是黑色的图形
        //这里也可以先读取一个本地或网络的图片,然后把图片转化为Bitmap的对象
        //接着进行压缩处处理再进行保存
        try {
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 从本地中读取图片,并显示在屏幕中
     */
    public void btn2(View v) {
        //需要读取权限
        String fileName = Environment.getExternalStorageDirectory().getAbsolutePath() + "/a1.jpg";
        Bitmap bmp = BitmapFactory.decodeFile(fileName);
        iv.setImageBitmap(bmp);

    }

    /**
     * 从网络中读取图片,并显示在屏幕中
     * 这里需要网络权限
     */
    public void btn3(View v) {
        //从网络
        //域名
        new Thread() {
            @Override
            public void run() {
                URL url = null;
                try {
                    //这里需要一个网络的图片的地址
                    url = new URL("http://img.mp.itc.cn/upload/20160411/f649cfdae0cd43929dedcd1e585f4a13_th.jpg");
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                }
                try {
                    //1.子线程无法刷新UI
                    //2.主线程无法请求网络
                    InputStream is = url.openStream();
                    final Bitmap bmp = BitmapFactory.decodeStream(is);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            iv.setImageBitmap(bmp);
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();


    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114

       如果Button的文本中,英文字母全部显示为大写,不管text中写的是大写还是小写,解决办法:在Button的属性里加上android:textAllCaps=”false”就行了,

       上面都是自定义View的简单使用,当然图像特效和动画的都和自定义的View有关系,另作总结。

Android动画的使用总结:
http://blog.csdn.net/wenzhi20102321/article/details/52955725
Android属性动画的示例:
http://blog.csdn.net/wenzhi20102321/article/details/52971572

 

发表评论

添加代码片

  • HTML/XML
  • objective-c
  • Ruby
  • PHP
  • C
  • C++
  • JavaScript
  • Python
  • Java
  • CSS
  • SQL
  • 其它

还能输入1000个字符

浅谈安卓自定义view(一):制作一个最最最简单的自定义view

wsyizmao wsyizmao

11-09 4734

对于安卓程序员来说,自定义view简直不要太重要,毕竟有很多功能,譬如圆形头像这些,用单纯的原生非常难以实现,而用自定义view,简直分分钟。在这里,我尝试用最简单方式跟初学者说一下如何自定义一个自己...

自定义View,有这一篇就够了

huachao1001 huachao1001

06-03 5.6万

我的简书同步发布:自定义View,有这一篇就够了 为了扫除学习中的盲点,尽可能多的覆盖Android知识的边边角角,决定对自定义View做一个稍微全面一点的使用方法总结,在内容并没有什么独特,其他大神...

Android 自定义View

chituhuan chituhuan

05-17 549

Android 自定义View一 简单的自定义ViewAndroid View 的绘制流程主要有 onMeasure, onLayout, onDraw. UI 内容的绘制主要在onDraw 中完成。...

Android自定义view之measure、layout、draw三大流程

zuguorui zuguorui

04-13 4567

自定义view之view显示流程 一个view要显示出来,需要经过测量、布局和绘制这三个过程,本章就这三个流程详细探讨一下。View的三大流程具体分析起来比较复杂,本文不会从根源详细地分析,但是可...

Android自定义View 一<最简单的自定义View>

qq_36209474 qq_36209474

03-19 3629

为什么要自定义Viewandroid提供了很多控件供我们使用 但有些功能是系统所提供的实现不 了的 这时候我们就需要自定义一个View来实现我们所需要的效果. 在Android中所有的控件都直...

Android自定义View绘制流程小结

wjw190077 wjw190077

01-24 999

总之一句话,当系统控件满足不了我们的需求时,就需要自定义View来实现,足以表达自定义有多么强大! 通过网上资料和结合自己实践,这篇文章主要用来理解绘制流程的一个具体过程的,绘制流程的起始都是在Vi...

Android自定义View实战】之你应该明白的事儿

u010785585 u010785585

10-24 3464

在Android的实际开发中,我们Android系统本身已经给我们提供了很丰富的UI以及各种实用的控件,例如TextView,Button,ImageView等。用这些基础控件已经能够实现非常优美的界...

手把手教你写一个完整的自定义View

carson_ho carson_ho

03-14 2.9万

前言 自定义View是Android开发者必须了解的基础 今天,我将手把手教你写一个自定义View,并理清自定义View所有应该的注意点 阅读本文前,请先阅读我写的一系列自定义View文章 ...

Android 自定义View (一)

lmj623565791 lmj623565791

04-21 40.4万

很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章。先总结下自定义View的步骤...

Android自定义view详解

pengpenggxp pengpenggxp

07-11 6358

对于我这样一个Android初级开发者来说,自定义View一直是一个遥不可及的东西,每次看到别人做的特别漂亮的控件,自己心里那个痒痒啊,可是又生性懒惰,自己不肯努力去看书,只能望而兴叹,每次做需求用到...

文章热词

android 运行时 闪退 android 扫描识别边框 android dot 指示器 android商品低价提醒 android返回快捷键

相关热词

android和 android】 android与 android框 android栈

自定义仪表盘控件(源码中已经改成了自己绘制表盘)

lqc1992 lqc1992

08-09 4598

新的任务又来了,这次需要实现一个仪表盘的自定义控件,自定义控件一不常写就手生,这次又巩固下,并且学了一些新知识。https://developer.android.com/training/custo...

Android自定义View的三种实现方式

luckrr luckrr

07-07 227

参考别人的文章,简明易懂,留个笔记  参考原文链接 在毕设项目中多处用到自定义控件,一直打算总结一下自定义控件的实现方式,今天就来总结一下吧。在此之前学习了郭霖大神博客上面关于自定义View的几...

自定义View Layout过程 - 最易懂的自定义View原理系列(3)

carson_ho carson_ho

02-20 1.4万

前言 自定义View是Android开发者必须了解的基础 网上有大量关于自定义View原理的文章,但存在一些问题:内容不全、思路不清晰、无源码分析、简单问题复杂化 等 今天,我将全面总结自定义V...

自定义view中onMeasure、onLayout、onDraw、onFinishInflate、onSizeChanged方法调用时机

anhenzhufeng anhenzhufeng

06-06 2409

一般自定义view或viewGroup基本上都会去实现onMeasure、onLayout、onDraw方法,还有另外两个方法是onFinishInflate和onSizeChanged。 on...

Android动态创建View

wenweidev wenweidev

09-07 1026

代码 View view = new View(context); LinearLayout.LayoutParams params = new LinearLayo...

自定义View基础 - 最易懂的自定义View原理系列(1)

carson_ho carson_ho

02-20 1.7万

前言 自定义View原理是Android开发者必须了解的基础; 在了解自定义View之前,你需要有一定的知识储备; 本文将全面解析关于自定义View中的所有知识基础。 目录1. View的分类视图Vi...

自定义View Measure过程 - 最易懂的自定义View原理系列(2)

carson_ho carson_ho

02-20 1.6万

前言 自定义View是Android开发者必须了解的基础 网上有大量关于自定义View原理的文章,但存在一些问题:内容不全、思路不清晰、无源码分析、简单问题复杂化 等 今天,我将全面总结自定义Vi...

Android自定义View注意事项

myth13141314 myth13141314

08-06 165

自定义View的分类 继承View重写onDraw方法 主要用于实现不规则的效果,即这种效果不方便通过布局的组合方式来实现。相当于就是得自己“画”了。采用这种方式需要自己支持wrap_cont...

Android自定义View-自定义组件

yilei0033 yilei0033

03-05 136

Android自定义组件 android自定义组件一般有三种实现方式: 一、组合控件:组合控件,顾名思义就是将一些小的控件组合起来形成一个新的控件,这些小的控件多是系统自带的控件。 二、自绘控件:...

Android 自定义View(一)

qq_15192113 qq_15192113

05-31 202

Android自定义View

Android自定义View入门---自定义一个TextView

jsonnan jsonnan

06-28 1290

自定义一个TextView本篇作为入门级介绍,以自定义TextView为案例,介绍一下自定义View的流程。自定义View玩的比较溜的小伙伴们可以略过。 简介 自定义View的类型 自定义View的套...

android 中的绘制类Paint 画笔,Canvas 画布,Bitmap 类和BitmapFactory及自定义属性

Dr_abandon Dr_abandon

11-23 2592

常用的绘图类是Paint 画笔,Canvas 画布,Bitmap 类和BitmapFactoryPaint类Paint类代表画笔,用来描述图形的颜色和风格,如线宽,颜色,透明度,和填充效果等信 息,...

Android自定义View的初步总结

yuminfeng728 yuminfeng728

06-08 4109

概述在开发过程中,经常会遇到系统中提供的控件无法满足产品的设计需求,这时可能就需要考虑使用自定义的View来实现产品的设计细节了。对于自定义View,可以分为两种,一种是自定义控件(继承View),另...

自定义控件玩套路以及canvas StaticLayout的使用

qq_28195645 qq_28195645

05-18 7479

自定义控件玩套路以及canvas StaticLayout的使用

Android自定义View总结(一)基础知识与实例

chen_lian_ chen_lian_

05-20 1122

Android中,View不属于四大组件,但它甚至比Receiver和Provider都要重要。 Android提供了许多基础的控件,但远远不能满足我们的需要,很多时候我们根据需求进行新控件的定义,这...

Android自定义View的用法总结

bigconvience bigconvience

05-23 4601

本文参考了:http://greenrobot.me/devpost/android-custom-layout/ Android SDK中提供了很多UI组件,如RelativeLayout, L...

下载

android 自定义View

12-13

android 自定义View android 自定义View

下载

自定义view

05-18

android自定义view,自定义属性的使用

下载

Android自定义View

03-20

Android中自定义View操作Android中自定义View操作Android中自定义View操作

Android 自定义view完全解析--带你通透了解自定义view

u011200604 u011200604

02-22 8767

参考转自郭霖博客带你一步步深入了解View系列 Android LayoutInflater原理分析 相信接触Android久一点的朋友对于LayoutInflater...

Android应用自定义View绘制方法手册

yanbober yanbober

04-04 3万

这篇迟迟难产的文章算是对2015前半年的一个交代吧,那时候有一哥们要求来一发Android Canvas相关总结,这哥们还打赏了,实在不好意思,可是这事一放就给放忘了,最近群里小伙伴催着说没更新博客,...

Android自定义View(二、深入解析自定义属性)

u010163442 u010163442

05-21 2.5万

转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51454685 本文出自:【openXu的博客】 [TOC] 在上一篇博...

简单说说Android自定义view学习推荐的方式

wingichoy wingichoy

01-08 9279

这几天比较受关注,挺开心的,嘿嘿。 这里给大家总结一下学习自定义view的一些技巧。 1.首先 去看看鸿洋神的博客 Android 自定义view(1). 鸿洋神的入门教程讲的很详细。再次膜拜...

自定义View自定义属性及引用

bobo8945510 bobo8945510

11-17 5510

学习导航….后续添加,自定义view不是一章能说清的。本章讲解: 自定义视图,我们需要做哪些准备!对于一些中级的开发者来说就要接触到自定义视图,由于Android自带的视图无法满足自己需求,又或者美观...

自定义View不能显示?来看看Studio怎么说!

github_37586705 github_37586705

10-16 942

android自定义view不显示

自定义View(三)---自定义View整个流程的梳理与总结

cjm2484836553 cjm2484836553

04-30 1280

转载请注明出处:From李诗雨—http://blog.csdn.net/cjm2484836553/article/details/71024436 不诗意的女程序猿不是好厨师~ 在自定义Vi...

Android自定义View高级(一)-分类与流程

u014005316 u014005316

01-19 1323

一.自定义View绘制流程二.自定义View分类 自定义ViewGroup 自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件,大多继承自ViewGroup或各种Layou...

Android-自定义View使用

githan githan

10-25 296

Android所有的控件都继承至View,所以我们可以通过继承View来实现自己想要的控件,具体代码如下:1,创建自定义View 类import android.content.Context; im...

Android - 自定义View不显示

u012246458 u012246458

12-06 3740

说明: 自定义了一个LinearLayout,显示不出来 原因是必须有 public ManDaoH5View(Context context, AttributeSet attrs) { 这个方法...

下载

Android自定义View之进度条Demo

10-23

Android自定义View之进度条Demo,Android自定义View之进度条Demo

自定义view-二,使用枚举

qq_15771061 qq_15771061

04-05 979

在自定义View中添加enum类型,类似android 中的match_parent和wrap_content

下载

android自定义view(一)——attire 使用

06-04

android自定义view(一)——attire 使用

Android使用handler和Runnable结合,自定义View更新UI的Demo

canghai1129 canghai1129

04-12 2449

前三周在修改android4.2锁屏UI,刚做android好多知识不会啊,里面有个动画效果是一个jian...

下载

自定义view解决android文本排版和换行问题

03-23

自定义view解决android文本排版和换行问题自定义view解决android文本排版和换行问题自定义view解决android文本排版和换行问题自定义view解决android文本排版和换行问题自定义view解决android文本排...

下载

android自定义view:十字按钮(用于智能家电APP)

12-02

本十字按钮可用于智能家电app,通过设置listener就可以监听四个方向的点击事件,同时其button的反应模式如系统给的button一致。在代码中也给出了另外五个普通按钮进行与十字按钮进行效果对比

自定义View——坑、技巧、调优

sinat_15877283 sinat_15877283

04-04 2620

相信有创建过“自定义View”经验的众多的开发者朋友当中有相当一部分人猿友是直接copy网上的一些代码拿来用,结果往往不尽如人意, 碰到bug或者是需求发生变化时往往手忙脚乱,android自定义Vi...

安卓自定义View进阶 - 贝塞尔曲线

u013831257 u013831257

04-29 1.4万

在上一篇文章Path之基本图形中我们了解了Path的基本使用方法,本次了解Path中非常非常非常重要的内容-贝塞尔曲线。...

Android自定义View的官方套路

yissan yissan

04-12 1.7万

概述Android已经为我们提供了大量的View供我们使用,但是可能有时候这些组件不能满足我们的需求,这时候就需要自定义控件了。自定义控件对于初学者总是感觉是一种复杂的技术。因为里面涉及到的知识点会比...

Android 自定义View之绘图

moira33 moira33

01-19 2074

【Android 自定义View之绘图】 Android 自定义View之绘图 基础图形的绘制 一Paint与Canvas Paint Paint的基本设置函数 setAntiAliastrue...

自定义View之基础篇

showdy showdy

12-10 579

Android APP屏幕区域划分: 1.状态栏区域: //获取屏幕区域的宽高等尺寸获取 DisplayMetrics metrics = new DisplayMetrics(); ...

没有更多推荐了,返回首页

个人资料

峥嵘life

已关注

原创

343

粉丝

617

喜欢

1035

评论

369

等级:

访问:

88万+

积分:

1万+

排名:

1874

勋章:

持之以恒

授予每个自然月内发布4篇或4篇以上原创或翻译IT博文的用户。不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累!

最新文章

  • Android 多线程之HandlerThread 详解
  • java判断一个字节数组在另一个字节数组的位置
  • 阿里巴巴的FastJson数据解析介绍
  • 讯飞语音识别和唤醒开发示例
  • 使用adb logcat命令显示Android设备上的Log日志

个人分类

  • android259篇
  • C语言基础6篇
  • java105篇
  • java集合4篇
  • java IO8篇
  • 数据库2篇
  • 人生感言13篇
  • Socket编程2篇
  • 面试13篇
  • java多线程6篇
  • Android文件资源使用11篇
  • UI42篇
  • Andr图形和动画7篇
  • Android多媒体3篇
  • 工具类13篇
  • android数据7篇
  • 消息处理机制3篇
  • 广播接收者1篇
  • 安卓服务2篇
  • Android网络25篇
  • 传感器1篇
  • 框架模式2篇
  • 插件4篇
  • 网络框架17篇
  • 高级控件13篇
  • xutils4篇
  • Fragment4篇
  • Vitamio1篇
  • 百度地图开发2篇
  • 设计模式25篇
  • ps17篇
  • webservice3篇
  • 报错情况3篇
  • dicom图像文件6篇
  • kotlin15篇

展开

归档

  • 2018年9月 3篇
  • 2018年8月 1篇
  • 2018年7月 5篇
  • 2018年6月 6篇
  • 2018年5月 5篇
  • 2018年4月 15篇
  • 2018年3月 12篇
  • 2018年2月 7篇
  • 2018年1月 1篇
  • 2017年12月 3篇
  • 2017年11月 7篇
  • 2017年10月 8篇
  • 2017年9月 7篇
  • 2017年8月 5篇
  • 2017年7月 20篇
  • 2017年6月 10篇
  • 2017年5月 14篇
  • 2017年4月 15篇
  • 2017年3月 23篇
  • 2017年2月 22篇
  • 2017年1月 9篇
  • 2016年12月 45篇
  • 2016年11月 26篇
  • 2016年10月 21篇
  • 2016年9月 45篇
  • 2016年8月 16篇

展开

热门文章

  • javaj经典程序编程50题

    阅读量:48214

  • java多线程的常见例子

    阅读量:32260

  • eclipse快捷键的设置和使用

    阅读量:30320

  • Android显示时间和日期的控件的使用总结

    阅读量:22081

  • Java IO流经典练习题

    阅读量:21601

最新评论

  • Android 多线程之Handl...

    headw:写的这是什么玩意。。。。。

  • Android一次申请多个动态权限

    weixin_39657438:转载了 楼主写的很清晰

  • 使用cmd根据WSDL网址生成ja...

    qq_41913924:[reply]Daisy_ljq[/reply] 在你发布webService的时候设置

  • Android网络定位或GPS定位

    weixin_40413165:大神,我按照您的程序写出,无法获取经纬度信息啊,就是什么都不显示,请教请教

  • 走穿java23种设计模式-3抽象...

    MirabelleZWH:谢谢分享

联系我们

客服

请扫描二维码联系客服

[email protected]

400-660-0108

QQ客服 客服论坛

关于招聘广告服务 网站地图

©2018 CSDN版权所有 京ICP证09002463号

百度提供搜索支持

经营性网站备案信息

网络110报警服务

中国互联网举报中心

北京互联网违法和不良信息举报中心

CSDN APP

  • 点赞取消点赞

    5

  • 评论

     

  • 目录
    1. 一View 的基本概念
      1. 一View的理解
      2. 二IDs
      3. 三获取View的位置信息
    2. 二View创建概述
      1. 一Creation创建流程
        1. 调用构造器
      2. 二Layout布局流程
        1. onMeasureint w int h 确定View和它所有的子View要求的尺寸时调用
        2. onLayoutboolean change int left int topint right int button 当这个View为其所有的子View指派一个尺寸和位置时调用
        3. onSizeChangedint w int h int oldw int oldh 当这个View的尺寸改变后调用
      3. 四Drawing绘制过程自定义View的重点方法哦
      4. 五Event事件流程
        1. onKeyDownint KeyEvent当一个新的键按下时
        2. onKeyUpint KeyEvent 当一个键弹起时
        3. onTrackballEventMotionEvent当滚迹球事件发生时
        4. onTouchEventMotionEvent当一个触摸屏事件发生时
      5. 五Focus焦点流程
        1. onFocusChangedboolean intRect 当View得到和失去焦点时调用
        2. onWindowFocusChangedboolean 当Window包含的View得到或失去焦点时调用
    3. 三定制View
      1. 一扩展View或者View的子类
      2. 二 必须实现其中一个构造方法一般都是实现两个
      3. 三重写onDrawcanvas方法进行绘制整个涉及到绘制任意的图像比如画线画圆画矩形等等
      4. 四如需调整大小重写onMesure默认是全屏的
      5. 五如需样式在xml中布置自定义属性
    4. 四测量布局MeasureSpec
      1. 一下面是各个模式的标志位表示
      2. 二这样表示一个View大小是很方便的我们来看下面的方法
        1. 下面是网友对MeasureSpec的一个理解
    5. 五常用的绘图类
      1. 一Paint类
        1. 常用方法paint
      2. 二Bitmap类
        1. compressBitmapCompressFormat format int quality OutputStream stream
        2. createBitmapBitmap source int x int y int width int height Matrix m boolean filter
        3. createBitmapBitmap source int x int y int width int height
      3. 三BitmapFactory类
        1. decodeFileString pathName 用于从给定的路径所指定的文件中解析创建Bitmap对象
      4. 四Canvas类
      5. 绘制几何图形
        1. 绘制文本
        2. 绘制路径
    6. 六自定义属性这个使用起来相对比较麻烦一般不用
      1. 一attsxml的文件
      2. 二自定义属性格式和意义
      3. 三在布局文件中使用自定义属性
      4. 四然后我们在自定义View中实现带AttributeSet属性的构造方法并且获取自定义值
    7. 七组合控件
      1. 一创建文件title_textxml
      2. 二接下来创建一个TitleView继承自FrameLayout代码如下所示
    8. 八绘制图片返回的都是一个Bitmap对象
      1. 一drawBitmapBitmap bitmap Rect src RectF dst Paint paint
      2. 二drawBitmapBitmap bitmap float left float top Paint paint
      3. 三drawBitmapBitmap bitmap Rect src Rect dst Paint paint
    9. 下面是一些程序的示例
    10. 九一个绘制简单图形图像的示例
      1. 一创建MyView继承View
      2. 二调用
    11. 十简易画板的实现
    12. 十一一个自定义的进度框框的显示
      1. 一自定义View的代码
      2. 二调用类的代码
      3. 三Xml文件
    13. 十二Bitmap对象的操作压缩保存和显示
      1. 一xml布局文件设计
      2. 二java代码

     

  • 收藏
  • 手机看
  • 上一篇
  • 下一篇
  • 更多
    • 上一篇
    • 下一篇

 

 

不良信息举报

 

举报内容:

Android自定义View使用总结

举报原因:

色情政治抄袭广告招聘骂人其他

原文地址:

 

原因补充:

最多只允许输入30个字

 

  •  
  • 博客
  • 学院
  • 下载
  • 图文课
  • TinyMind
  • 论坛
  • APP

  • 问答
  • 商城
  • VIP会员
  • 活动
  • 招聘
  • ITeye
  • GitChat
  •  
  •  

  • 写博客
  • 发Chat
  • 传资源
  • 登录注册
  • 个人中心

    我的博客

    消息(3)

    创作中心

    帐号设置

    我的C币

    订单中心

    帮助

    退出

  • 简单说说Android自定义view学习推荐的方式

    01-08 9279
  • 自定义View—自定义属性及引用

    11-17 5510
  • 自定义View不能显示?来看看Studio怎么说!

    10-16 942
  • 自定义View(三)---自定义View整个流程的梳理与总结

    04-30 1280
  • Android自定义View高级(一)-分类与流程

    01-19 1323
  • Android-自定义View的使用

    10-25 296
  • Android - 自定义View不显示

    12-06 3740
  • 下载

    Android自定义View之进度条Demo

    10-23
  • 自定义view-二,使用枚举

    04-05 979
  • 下载

    android自定义view(一)——attire 使用

    06-04
  • Android使用handler和Runnable结合,自定义View更新UI的Demo

    04-12 2449
  • 下载

    自定义view解决android文本排版和换行问题

    03-23
  • 下载

    android自定义view:十字按钮(用于智能家电APP)

    12-02
  • 自定义View——坑、技巧、调优

    04-04 2620
  • 安卓自定义View进阶 - 贝塞尔曲线

    04-29 1.4万
  • Android自定义View的官方套路

    04-12 1.7万

Android自定义View使用总结

2016年11月29日 16:49:19 峥嵘life 阅读数:3148 标签: android widget 自定义View 更多

个人分类: Andr图形和动画 android

版权声明:本文为博主原创文章。只要评论中留言就可以转载。 https://blog.csdn.net/wenzhi20102321/article/details/53395111

      很多人把自定义View想象得很复杂,其实一步一步的去理解记忆,它的知识点并不是很难,但是它的应用方向确实是比较多。本文先简单的介绍一下自定义View和它的使用。

一.View 的基本概念

(一)View的理解

       View是一个Android视图的基础类,这个类是用户接口的基础构件。 View 表示屏幕上的一块矩形区域,负责绘制这个区域和事件处理。 View 是所有widget类的基类,Widget 类用于创建交互式UI构件(按钮,输入框等)。 View 类的ViewGroup子类是layout的基类,Layout是一个不可见的容器,它保存着 View(或ViewGroup)并定义这些View的layout属性。 可以说View类是用户视图接口类中最重要的一个类,就像Object类是所有类的基础父类相似,不过View是针对的是视图。

(二)IDs:

        Views 有一个整数相对应,id被用于在View树中找到指定的View。可以在layout文件中 定义 一个唯一的ID, 在Activity的onCreate函数中调用findViewById来查找这个View。 在整个树内,id可以不是唯一的,但再指定的范围内查找时我们可以确信它是唯一的。比如不同的xml布局文件中可以存在相同id编号,但是同一个xml布局文件中不能存在相同的id编号。

(三)获取View的位置信息

View是一个矩形区域, 使用左&上的坐标以及长和宽可以表示一个View。我们可以使用方 法getLeft() , getTop(),getRight(),getBottom(),getWidth(),getHeight()等函数来获取其位置信息.

二.View创建概述

在API中对View的回调流程有以个详细的描述:

(一)Creation:创建流程

1.调用构造器

public View(Context context) //使用java代码创建View时的构造方法
public View(Context context, AttributeSet attrs)//在XML中配置时的构造 方法,attrs存储xml中设置的属性
上面这两个构造方法都是要重写的,哪怕只是使用其中一个。并且初始化数据在这两个构造方法都要做一遍。
2.onFinishInflate() //当View和他的所有子View从XML中解析完成后调用。 一般不怎么用!

(二)Layout:布局流程

1.onMeasure(int w, int h) //确定View和它所有的子View要求的尺寸时调用

2.onLayout(boolean change, int left, int top,int right, int button) //当这个View为其所有的子View指派一个尺寸和位置时调用

3.onSizeChanged(int w, int h, int oldw, int oldh) //当这个View的尺寸改变后调用

(四)Drawing:绘制过程(自定义View的重点方法哦)

onDraw(Canvas) //当View给定其内容时调用

(五)Event:事件流程

1.onKeyDown(int, KeyEvent)//当一个新的键按下时

2.onKeyUp(int, KeyEvent) //当一个键弹起时

3.onTrackballEvent(MotionEvent)//当滚迹球事件发生时

4.onTouchEvent(MotionEvent)//当一个触摸屏事件发生时

(五)Focus:焦点流程

1.onFocusChanged(boolean, int,Rect) //当View得到和失去焦点时调用

2.onWindowFocusChanged(boolean) //当Window包含的View得到或失去焦点时调用。

三.定制View

      为了实现一个定制View, 需要重写一些View的标准方法。 framework会调用这些方法, 并且认为这些方法应该是所有的view都有实现。 这些方法不必全部重写。
      事实上,可以只重写onDraw方法就可以了自定义View的步骤:

(一)扩展View或者View的子类。

例如:
class MyView extends View
class MyView extends TextView
class MyView extends LinearLayout
class MyView extends ViewPager
  • 1
  • 2
  • 3
  • 4
  • 5

      这些都是自定义View的扩展,比如继承了TextView可以直接使用它的方法,setText(“xxx”);setBackColor(0xf00);等等。

(二) 必须实现其中一个构造方法,一般都是实现两个。

(三)重写onDraw(canvas)方法进行绘制,整个涉及到绘制任意的图像,比如画线,画圆,画矩形等等。

(四)如需调整大小,重写onMesure,默认是全屏的。

(五)如需样式在xml中布置,自定义属性。

这相当于静态使用View,比如

  • 1
  • 2
  • 3
  • 4
  • 5

      这里在静态布局中看不出什么设置,但是在MyView中可以做很多设置,比如设置好里面的文本字体、背景、甚至里面对应控件的点击事件都是可以预先在MyView中设置好的。

四.测量布局MeasureSpec

      在View系统中,指定宽和高,以及指定布局的属性,是由MeasureSpec来封装的。

(一)下面是各个模式的标志位表示。

1.private static final int MODE_SHIFT = 30;   
2.private static final int MODE_MASK  = 0x3 << MODE_SHIFT;   
3.public static final int UNSPECIFIED = 0 << MODE_SHIFT; 
4.public static final int EXACTLY     = 1 << MODE_SHIFT;
5.public static final int AT_MOST     = 2 << MODE_SHIFT;  
  • 1
  • 2
  • 3
  • 4
  • 5

      在这个解析系统中是通过移位来存放更多的数据,现在每个数据标志位都向左移动了30位。

(二)这样表示一个View大小是很方便的,我们来看下面的方法:

1.public static int makeMeasureSpec(int size, int mode) { 
  return size + mode;  
 }  
  • 1
  • 2
  • 3

      通过这个方法就可以制作一个含有两个参数的int值,这个参数包含一个mode标志和一个宽或高的表示。

2.public static int getMode(int measureSpec) {   
    return (measureSpec & MODE_MASK);    
     }  
  • 1
  • 2
  • 3

      通过方法来获取到mode。

3. public static int getSize(int measureSpec) {  
           return (measureSpec & ~MODE_MASK);    
}  
  • 1
  • 2
  • 3

      用方法来获取高或宽的数据。

      测量这个View的高和宽。通过调用这个方法来设置View的测量后的高和宽,其最终调用的方 法是:

4.protected final void setMeasuredDimension(int measuredWidth, in t measuredHeight) { 
 mMeasuredWidth = measuredWidth; 
 mMeasuredHeight = measuredHeight;  
 mPrivateFlags |= MEASURED_DIMENSION_SET;    
       }  
  • 1
  • 2
  • 3
  • 4
  • 5

      可见其最终是将高和宽保存在mMeasuredWidth、mMeasuredHeight这两个参数中。

下面是网友对MeasureSpec的一个理解:

在自定义View和ViewGroup的时候,我们经常会遇到int型的MeasureSpec来表示一个组件的大小,这个变量里面不仅有组件的尺寸大小,还有大小的模式。

这个大小的模式,有点难以理解。在系统中组件的大小模式有三种:

1.精确模式
在这种模式下,尺寸的值是多少,那么这个组件的长或宽就是多少。

2.最大模式
这个也就是父组件,能够给出的最大的空间,当前组件的长或宽最大只能为这么大,当然也可以比这个小。

3.未指定模式
这个就是说,当前组件,可以随便用空间,不受限制。

可能有很多人想不通,一个int型整数怎么可以表示两个东西(大小模式和大小的值),
一个int类型我们知道有32位。而模式有三种,要表示三种状态,至少得2位二进制位。
于是系统采用了最高的2位表示模式:

最高两位是00的时候表示"未指定模式"。即MeasureSpec.UNSPECIFIED
最高两位是01的时候表示"'精确模式"。即MeasureSpec.EXACTLY
最高两位是11的时候表示"最大模式"。即MeasureSpec.AT_MOST


很多人一遇到位操作头就大了,为了操作简便,于是系统给我提供了一个MeasureSpec工具类。
这个工具类有四个方法和三个常量(上面所示)供我们使用:


//这个是由我们给出的尺寸大小和模式生成一个包含这两个信息的int变量,这里这个模式这个参数,传三个常量中的一个。
public static int makeMeasureSpec(int size, int mode)


//这个是得到这个变量中表示的模式信息,将得到的值与三个常量进行比较。
public static int getMode(int measureSpec)


//这个是得到这个变量中表示的尺寸大小的值。
public static int getSize(int measureSpec)


//把这个变量里面的模式和大小组成字符串返回来,方便打日志
 public static String toString(int measureSpec)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

五.常用的绘图类

      常用的绘图类是Paint 画笔,Canvas 画布,Bitmap 类和BitmapFactory。

(一)Paint类

      Paint类代表画笔,用来描述图形的颜色和风格,如线宽,颜色,透明度,和填充效果等信息,使用Paint时,需要先创建该类的对象,这可以通过该类提供的构造方法来实现。通常情况下,只需要使用无参数的构造方法来创建一个使用默认设置的Paint对象:

Panit paint=new Panint();

常用方法paint.:

  1. setARGB(int a, int r, int g, int b) 用于设置颜色,各参数值均为0~255之间的整数,分别用于表示透明度、红色、绿色和蓝色值
  2. setColor(int color) 用于设置颜色,参数color可以通过Color类提供的颜色常量指定
    3.Color.rgb(in t red,int green,int blue)方法指定颜色
  3. setAlpha(int a) 用于设置透明度,值为0~255之间的整数
  4. setAntiAlias(boolean aa) 用于指定是否使用抗锯齿功能,如果使用会使绘图速度变慢 ,但是一般图像绘制都会设置使用。
    6.setDither(boolean dither) 用于指定是否使用图像抖动处理,如果使用会使图像颜色更加平滑和饱满,更加清晰
  5. setShader(Shader shader) 用于设置渐变,可以使用LinearGradient(线性渐变)、RadialGradient(径向渐变)或 者SweepGradient(角度渐变),后面分别做详细介绍 8.setStrokeWidth(float width) 用于设置笔触的宽度 9. setStyle(Paint.Style style) 用于设置填充风格,参数值 为Style.FILL表示实心、Style.FILL_AND_STROKEStyle.STROKE表示空心 10.setTextAlign(Paint.Align align) 用于设置绘制文本时的文字对齐方式,参数值为Align.CENTERAlign.LEFTAlign.RIGHT
  6. setTextSize(float textSize) 用于设置绘制文本时的文字的大小

12.渐变的几种表示形式
(1)线性渐变
new LinearGradient(0, 0, 50, 50, Color.RED, Color.GREEN, Shader.TileMod e.MIRROR);
参数一为渐变起初点坐标x位置
参数二为y轴位置
参数三和四分别对应渐变终点
最后参数为平铺方式,这里设置为镜像

(2)径向渐变
new RadialGradient(160, 110, 50, Color.RED, Color.GREEN, Shader.TileMod e.MIRROR);
参数一,参数二为渐变圆中心坐标
参数三为半径
参数四,参数五
参数六为平铺方式

(3)角度渐变
new SweepGradient(265, 110, new int[] { Color.RED, Color.GREEN, Color.B LUE }, null);
参数一参数二为渲染中心点x,y坐标
参数三为围绕中心渲染的颜色数组,至少要有两种颜色值
参数四为相对位置的颜色数组,若为null,颜色沿渐变线均匀分布

(二)Bitmap类

      Bitmap类代表位图,它是Android系统中图像处理的最重要类之一,使用它不仅可以获取图像文件信息,进行图像剪切,旋转,缩放等操作,而且还可以指定格式保存图像文件。 Bitmap类常用的方法

1. compress(Bitmap.CompressFormat format, int quality, OutputStream stream)

用于将Bitmap对象压缩为指定格式并保存到指定的文件输出流中,简单的说就是能保存一个图片到本地。
参数一:数值可以是Bitmap.CompressFormat.PNG、Bitmap.CompressFormat. JPEG和Bitmap.Compres sFormat.WEBP
参数二:0到100,100为最大品质值,
参数三:输出流,可以是文件输出流输出保存到本地,可以是网络输出流对应的就会输出到网络中。

2.createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)

用于从源位图的指定坐标点开始,“挖取”指定宽度和高度的一块图像来创建新的Bitmap对象,并按Matrix指定规则进行变换
参数一:要被挖取的Bitmap对象
参数二三:开始挖的左边和上边的位置
参数四五:要挖宽度和高度。
参数六:一个枚举类型的配置,可以定义截到的新位图的质量

最后一个参数:filter解释:
true if the source should be filtered. Only applies if the matrix contains more than just translation.
当进行的不只是平移变换时,filter参数为true可以进行滤波处理,有助于改善新图像质量;flase时,计算机不做过滤处理。
要想imageView.setImageMatrix()方法起作用,xml得配置android:scaleType="matrix"
matrix.setRotate和matrix.postRotate的区别:
post...:平移、旋转等效果可以叠加在一起;
set...:前一种效果会消失,只有后来的操作,即它会重置Matrix
3.createBitmap(int width, int height, Bitmap.Config config) 
用于创建一个指定宽度和高度的新的Bitmap对象
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

4.createBitmap(Bitmap source, int x, int y, int width, int height)

      用于从源位图的指定坐标点开始,“挖取”指定宽度、和高度的一块图像来创建新的Bitmap对象
5.createBitmap(int[] colors, int width, int height, Bitmap.Config config)
使用颜色数组创建一个指定宽度和高度的新Bitimap对象,其中,数组元素的个数为width*height
6.createBitmap(Bitmap src) 用于使用源位图创建一个新的Bitmap对象
7. createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)用于将源位图缩放为指定宽度和高度的新的Bitmap对象
8.isRecycled() 用于判断Bitmap对象是否被回收 9.recycle() 强制回收Bitmap对象

(三)BitmapFactory类

      该类为一个工具类,用于从不同的数据源来解析,创建BitMap对象。

1.decodeFile(String pathName) 用于从给定的路径所指定的文件中解析、创建Bitmap对象

2.decodeResource(Resources res, int id) 用于根据给定的资源ID从指定的资源中解析、创建 Bitmap对象 3.decodeStream(InputStream is) 用于从指定的输入流中解析、创建Bitmap对象

      思 考 : 如 何 从 S D 卡 中 解 析 图 片 文 档 并 显 示 到 G r i d V i e w 中
String path = Environment.getExternalStorageDirectory() + “/”; 得到sdcard路径

(四)Canvas类

      通过该类提供的方法,可以绘制各种图形,如,矩形,圆形,和线条等,通常情况下,要在 Andaroid中绘图,需要先创建一个继承自View类的视图,并且在该类中重写它的 onDraw(Canvas canvas)方法,然后在显示绘图的Activity中添加该视图。

1.绘制几何图形

Android提供了强大的二维图形库,比较常用的是绘制几何图形,绘制文本,路径和图片等 比较常见的图形包括点,线,弧,圆形,矩形,在Android中,Canvas类提供了丰富的绘制几何图形的 方法,通过这些方法可以绘制出各种几何图形,常用的绘制几何图形的方法如下:

  1)填充
      drawARGB(int a, int r, int g, int b)
      drawColor(int color)
      drawRGB(int r, int g, int b)
      drawColor(int color, PorterDuff.Mode mode)
  2)几何图形
     canvas.drawArc (扇形)
     canvas.drawCircle(圆)
     canvas.drawOval(椭圆)
     canvas.drawLine(线)
     canvas.drawPoint(点)
     canvas.drawRect(矩形)
     canvas.drawRoundRect(圆角矩形)
     canvas.drawVertices(顶点)
     cnavas.drawPath(路径)
   3)图片
       canvas.drawBitmap (位图)
       canvas.drawPicture (图片)
   4)文本
       canvas.drawText
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

2.绘制文本

      在Android中,可以通过TextView来显示文本,但是,在开发游戏时,特别是开发RPG类游戏时,会包含很多文字 ,使用TextView和图片显示文本不太合适,这时,就需要通过绘制文本的方式来实 现,Canvas类提供了一系列的绘制文本的方法,

(1) drawText(String text,float x,float y, Paint paint)

参数分别是,要绘制的文本,文字的起始位置X坐标,文字起始位置的Y坐标

(2) drawPosText(String text,float[] pos Paint paint)

参数分别是,要绘制的文本,每个字符的位置,该方法已过期.

(3)文字对齐使用Paint的TextAlign(xxx);

3.绘制路径

      在Android中,提供了绘制路径的功能,绘制一条路径可以分为创建路径和绘制定义好的路径两部分创建路径: 使用android.graphics.Path类来实现,Path类包含一组矢量绘图方法,如,画圆,矩形,弧,线条 等,常用的方法如下
(1) addArc(RectF oval, float startAngle, float sweepAngle) 添加弧形的路径
(2)addCircle(float x, float y, float radius, Path.Direction dir) 添加圆形的路径 //Path.Direction类型的常量,可选值为Path.Direction.CW(顺时针)和Path.Directio n.CCW(逆时针).下面同。
(3) addOval(RectF oval, Path.Direction dir) 添加椭圆形路径
(4) addRect(RectF rect, Path.Direction dir) 12. 添加矩形路径
(5)addRoundRect(RectF rect, float rx, float ry, Path.Direction dir) 添加圆角矩形路径
(6)moveTo(float x, float y) 设置开始绘制直线的起始点
(7)lineTo(float x, float y) 在moveTo()方法设置的起始点与该方法指定的结束点之间画一条直线,如果在调用该方法之前没使用moveTo()方法设置起始点,那么将从(0,0)点开始绘制直线
(8)quadTo(float x1, float y1, float x2, float y2)
用于根据指定的的参数绘制一条线段轨迹
(9)close() 闭合路径

六.自定义属性,这个使用起来相对比较麻烦,一般不用

我们在XML布局下经常使用的id,layout_width,layout_height等等参数,那么我们如何定义自 己的属性呢?

(一)atts.xml的文件


  

     
 

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

(二)自定义属性格式和意义

1. reference       引用 
2. color           颜色 
3. boolean         布尔值 
4. dimension       尺寸值 
5. float           浮点值 
6. integer         整型值 
7. string          字符串 
8. enum            枚举值
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

(三)在布局文件中使用自定义属性

  
android:layout_height="wrap_content"
app:textColor="#f00" 
app:textSize="20dp" /> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

(四)然后我们在自定义View中实现带AttributeSet属性的构造方法,并且获取自定义值

public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
 //将属性数组提取出来 
 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.M yView); 
//获取对应的自定义属性,并且给默认值
 int textColor = a.getColor(R.styleable.MyView_textColor, 8.                 0X000000); 
 float textSize = a.getDimension(R.styleable.MyView_textSize, 36); 
//将值设置给画笔,绘画后颜色和大小就已经改变成我们自定义属性的值 
 mPaint.setTextSize(textSize); 
mPaint.setColor(textColor); 
//释放 
 ta.recycle();
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

      在执行完之后,一定要确保调用recycle() 方法。用于检索从这个结构对应于给定的属性位置 到obtainStyledAttributes中的值。

七.组合控件

      组合控件的意思就是,我们并不需要自己去绘制视图上显示的内容,而只是用系统原生的控件就好了,但我们可以将几个系统原生的控件组合到一起,这样创建出的控件就被称为组合控件。
      举个例子来说,标题栏就是个很常见的组合控件,很多界面的头部都会放置一个标题栏,标题 栏上会有个返回按钮和标题,点击按钮后就可以返回到上一个界面。
那么下面我们就来尝试去 实现这样一个标题栏控件。

(一)创建文件title_text.xml

  

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

      在这个布局文件中,我们首先定义了一个RelativeLayout作为背景布局,然后在这个布局里定 义了一个Button和一个TextView,Button就是标题栏中的返回按钮,TextView就是标题栏中 的显示的文字。

(二)接下来创建一个TitleView继承自FrameLayout,代码如下所示:

public class TitleView extends FrameLayout { 
private Button leftButton; 
private TextView titleText;  
public TitleView(Context context, AttributeSet attrs) { 
        super(context, attrs); 
//加载布局,并加入当前视图 
LayoutInflater.from(context).inflate(R.layout.title, this); 
titleText = (TextView) findViewById(R.id.title_text); 
leftButton = (Button) findViewById(R.id.button_left); 
leftButton.setOnClickListener(new OnClickListener() {
             @Override  
public void onClick(View v) { 
((Activity) getContext()).finish(); 
 }  
 });  
 } 
public void setTitleText(String text) { 
titleText.setText(text);
}  
public void setLeftButtonText(String text) { 
        leftButton.setText(text);  
    } 
    public void setLeftButtonListener(OnClickListener l) { 
       leftButton.setOnClickListener(l); 
    } 
 }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

      其中这个组合控件相对来说是比较灵活的,上面的标题和返回的文本都是可以替换的,并且返回的点击的监听事件是可以重写的。

八.绘制图片,返回的都是一个Bitmap对象

(一)drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)

用于从指定点绘制从源位图中“挖取”的一块拉伸

(二)drawBitmap(Bitmap bitmap, float left, float top, Paint paint)

用于在指定点绘制位图

(三)drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)

用于从指定点绘制从源位图中“挖取”的一块

下面是一些程序的示例…

九.一个绘制简单图形图像的示例

绘制效果:
Android自定义View使用总结_第13张图片
这里只是做各种图像绘制的展示。具体代码:

(一)创建MyView继承View

package com.example.myview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.view.View;

/**
 * 创建自定义View并使用其中的简单方法
 */

public class MyView extends View {
    public MyView(Context context) {
        super(context);
        initView();
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }



    //创建画笔
    Paint paint = new Paint();
    //设置一个圆心的点
    Point point = new Point();

    //初始化数据
    void initView() {
        //对画笔的基本设置
        //设置抗锯齿
        paint.setAntiAlias(true);
        //设置防抖动
        paint.setDither(true);
        //设置颜色
        paint.setColor(Color.RED);
        //设置透明的
        paint.setAlpha(128);
        //设置线条粗细
        paint.setStrokeWidth(10);
        point.set(getResources().getDisplayMetrics().widthPixels / 2, getResources().getDisplayMetrics().heightPixels / 2);

    }

    //View的视图绘制的回调方法
    //使用的是参数里面的canvas画板对象来进行各项操作
    RectF rectF = new RectF(10, 200, 400, 400);
    RectF rectF2 = new RectF(10, 650, 400, 800);

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制一条直线
        canvas.drawLine(10, 10, 100, 10, paint);
        //绘制多条直线
        canvas.drawLines(new float[]{10, 30, 200, 30, 10, 50, 300, 50,}, paint);
        //绘制一个实心圆(默认情况)
        canvas.drawCircle(point.x, point.y, 50, paint);
        //绘制一个点,这里的点是正方形的
        canvas.drawPoint(10, 300, paint);
        //绘制一个椭圆,参数直接写里面的一个方法对API等级有限制
        canvas.drawOval(rectF, paint);
        //绘制一个矩形
        canvas.drawRect(10, 400, 100, 600, paint);
        //绘制圆角矩形
        canvas.drawRoundRect(rectF2, 50, 50, paint);
        //绘制文本
        canvas.drawText("你好世界小姐", 0, paint.getTextSize(), paint);
        canvas.drawText("你好中心小姐", point.x, point.y, paint);
        //对画笔的其他设置
        paint.setTextSize(30);
        paint.setTextAlign(Paint.Align.CENTER);
        canvas.drawText("你好正中心小姐", point.x, point.y, paint);
        //画一个空心圆也设置画笔
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(point.x, point.y + 200, 50, paint);
        //设置画笔的渐变效果
        //线性渐变
        //  paint.setShader(new LinearGradient(10,650,200,800,Color.RED,Color.BLUE, Shader.TileMode.MIRROR));
        //径向渐变,像一个圆从圆点向四周扩散
        // paint.setShader(new RadialGradient(point.x,point.y,100,Color.BLACK,Color.YELLOW, Shader.TileMode.REPEAT));
        //角度渐变
        paint.setShader(new SweepGradient(100, 100, new int[]{Color.BLUE, Color.GREEN,Color.RED}, null));

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93

(二)调用

方法1:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

方法2:

(1)java代码

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

(2)xml文件代码:




    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

      其中使用第一个方法,整个页面都是MyView的显示,使用第二个调用方法,可以在xml布局文件内添加其他的控件。

十.简易画板的实现

      程序实现在页面上显示一个跟随手指移动的小球,并且随着小球的移动,留下绘制的路线。
效果如图所示:
Android自定义View使用总结_第14张图片
程序设计的代码:

package com.lwz.path;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * 使用小圆绘制图像
 */

public class TouchView extends View {
    public TouchView(Context context) {
        super(context);
        initView();
    }

    public TouchView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    //定义画笔
    Paint paint;
    //定义一个圆点
    PointF pointf;

    //定义路径
    Path path;

    //初始化数据
    private void initView() {
        paint = new Paint();
        paint.setDither(true);
        paint.setAntiAlias(true);
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        pointf = new PointF();

        path = new Path();
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        //绘制图像,这里绘制无数个圆点组成图像
       canvas.drawCircle(pointf.x, pointf.y, 10, paint);
        canvas.drawPath(path,paint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x=event.getX();
        float y=event.getY();

        if (event.getAction() == MotionEvent.ACTION_DOWN){
            path.moveTo(x,y);
        }
        //移动就绘制图像
        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            //设置点的坐标//这个重新绘制很重要
            pointf.set(event.getX(), event.getY());
            //绘制路径
            path.lineTo(x,y);
        }
        invalidate();

        return true;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

调用类的方法:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(new TouchView(this));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

十一.一个自定义的进度框框的显示

程序效果:
Android自定义View使用总结_第15张图片

      这里设计两个空心圆,一个圆是直接绘制好的,另一个是随着进度而进行绘制,。
这里还使用画笔绘制文字,也是随着进度而改变。

进度执行完成后的显示效果:
Android自定义View使用总结_第16张图片
程序设计的代码:

(一)自定义View的代码

package com.lwz.myprogressbar;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

/**
 * 绘制一个自定义的进度条的显示
 */

public class MyProgressBar extends View {
    public MyProgressBar(Context context) {
        super(context);
        initView();
    }

    public MyProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        //获取布局文件内的自定义属性
       /*  TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ArcProgressBar);
        //取出我们的属性
        max = a.getInt(R.styleable.ArcProgressBar_max, 100);
        progress = a.getInt(R.styleable.ArcProgressBar_progress, 0);
        //一定要释放
        a.recycle();*/

        initView();
    }

    //定义画笔
    Paint paint;
    Paint paint2;
    Paint textPaint;
    //最大的进度值
    private int max = 100;
    //当前的进度值
    private int progress = 0;
    //定义圆的中心点的x轴坐标
    int width;

    //定义圆点的坐标
    RectF oval;

    //测量布局时的回调方法
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取宽度
        width = getWidth();
        //确定圆的坐标位置
        oval = new RectF(width / 2 - 100, width / 2 - 100, width / 2 + 100, width / 2 + 100);
    }

    //初始化数据
    private void initView() {
        //画圆的画笔
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setStyle(Paint.Style.STROKE);//设置空心圆形式
        paint.setStrokeWidth(3);//设置边框宽度

        paint2 = new Paint();
        paint2 = paint;
        //文字的画笔
        textPaint = new Paint();
        textPaint.setAntiAlias(true);
        textPaint.setDither(true);
        textPaint.setTextAlign(Paint.Align.CENTER);//设置文字居中
        textPaint.setColor(Color.BLUE);//设置字体颜色蓝色
        textPaint.setTextSize(30);//设置字体大小
    }

    //绘制图形
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(Color.GRAY);//设置画笔颜色
        //绘制一个圆并把它放在中心
        canvas.drawCircle(width / 2, width / 2, 100, paint);

        //设置弧度颜色
        paint.setColor(Color.RED);
        //绘制一个弧度代表进度,动态更新
        canvas.drawArc(oval, -90, (int) (progress * 1f / max * 360), false, paint);
        //设置显示的文本
        textPaint.setTextAlign(Paint.Align.CENTER);
        //动态更新进度的数值
        canvas.drawText((int) ((progress * 1f / max) * 100f) + "%", width / 2, width / 2, textPaint);

    }

    //模拟资源下载
    public void startToProgress() {
        new Thread() {
            @Override
            public void run() {
                super.run();
                //执行任务
                while (progress < max) {
                    progress++;
                    try {
                        sleep(200);
                    } catch (InterruptedException e) {
                    }
                    //刷新进度条
                    postInvalidate();
                }
                //任务完成后,给主线程发送一个消息
                if (onProgressCompleteListener != null) {
                    onProgressCompleteListener.onFinish();
                }
            }
        }.start();
    }

    //1.创建监听
    public interface OnProgressCompleteListener {
        void onFinish();
    }


    //2.创建接口对象
    OnProgressCompleteListener onProgressCompleteListener;

    //3. set方法,里面的参数接口对象
    public void setOnProgressCompleteListener(OnProgressCompleteListener onProgressCompleteListener) {
        this.onProgressCompleteListener = onProgressCompleteListener;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134

(二)调用类的代码

package com.lwz.myprogressbar;

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

public class MainActivity extends AppCompatActivity implements MyProgressBar.OnProgressCompleteListener {
    MyProgressBar myView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myView = (MyProgressBar) findViewById(R.id.main_apb);
        //开始任务
        myView.startToProgress();
        //给自定义的视图添加监听事件
        myView.setOnProgressCompleteListener(this);

    }

    //任务完成后显示
    @Override
    public void onFinish() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getBaseContext(), "执行完毕", Toast.LENGTH_LONG).show();
            }
        });

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

(三)Xml文件




    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

十二.Bitmap对象的操作,压缩保存和显示

程序运行后的效果:

Android自定义View使用总结_第17张图片
Android自定义View使用总结_第18张图片
第二个和第三个按钮的效果差不多,这里就不演示了。

下面是代码

(一)xml布局文件设计




    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

(二)java代码

package com.example.bitmap;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

public class MainActivity extends AppCompatActivity {
    //定义一个Bitmap对象
    Bitmap bmp;
    //定义布局内的ImageView控件对象
    ImageView iv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        iv = (ImageView) findViewById(R.id.main_iv);
        //创建一个Bitmap对象,里面啥都没有
        //200*200 = 40000 = 40b 1024
        bmp = Bitmap.createBitmap(200, 200, Bitmap.Config.RGB_565);
        iv = (ImageView) findViewById(R.id.main_iv);
        //给ImageView设置一个Bitmap对象,默认是一块黑色的区域
        iv.setImageBitmap(bmp);


    }

    /**
     * 图片的保存
     */
    public void btn1(View v) {
        //jpg没有透明度
        //获取手机内的一个图片的地址
        String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/aa.png";
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(path);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        //压缩图片并进行保存的实际操作
        bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
        //这里保存的是黑色的图形
        //这里也可以先读取一个本地或网络的图片,然后把图片转化为Bitmap的对象
        //接着进行压缩处处理再进行保存
        try {
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 从本地中读取图片,并显示在屏幕中
     */
    public void btn2(View v) {
        //需要读取权限
        String fileName = Environment.getExternalStorageDirectory().getAbsolutePath() + "/a1.jpg";
        Bitmap bmp = BitmapFactory.decodeFile(fileName);
        iv.setImageBitmap(bmp);

    }

    /**
     * 从网络中读取图片,并显示在屏幕中
     * 这里需要网络权限
     */
    public void btn3(View v) {
        //从网络
        //域名
        new Thread() {
            @Override
            public void run() {
                URL url = null;
                try {
                    //这里需要一个网络的图片的地址
                    url = new URL("http://img.mp.itc.cn/upload/20160411/f649cfdae0cd43929dedcd1e585f4a13_th.jpg");
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                }
                try {
                    //1.子线程无法刷新UI
                    //2.主线程无法请求网络
                    InputStream is = url.openStream();
                    final Bitmap bmp = BitmapFactory.decodeStream(is);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            iv.setImageBitmap(bmp);
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();


    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114

       如果Button的文本中,英文字母全部显示为大写,不管text中写的是大写还是小写,解决办法:在Button的属性里加上android:textAllCaps=”false”就行了,

       上面都是自定义View的简单使用,当然图像特效和动画的都和自定义的View有关系,另作总结。

Android动画的使用总结:
http://blog.csdn.net/wenzhi20102321/article/details/52955725
Android属性动画的示例:
http://blog.csdn.net/wenzhi20102321/article/details/52971572

 

发表评论

添加代码片

  • HTML/XML
  • objective-c
  • Ruby
  • PHP
  • C
  • C++
  • JavaScript
  • Python
  • Java
  • CSS
  • SQL
  • 其它

还能输入1000个字符

浅谈安卓自定义view(一):制作一个最最最简单的自定义view

wsyizmao wsyizmao

11-09 4734

对于安卓程序员来说,自定义view简直不要太重要,毕竟有很多功能,譬如圆形头像这些,用单纯的原生非常难以实现,而用自定义view,简直分分钟。在这里,我尝试用最简单方式跟初学者说一下如何自定义一个自己...

自定义View,有这一篇就够了

huachao1001 huachao1001

06-03 5.6万

我的简书同步发布:自定义View,有这一篇就够了 为了扫除学习中的盲点,尽可能多的覆盖Android知识的边边角角,决定对自定义View做一个稍微全面一点的使用方法总结,在内容并没有什么独特,其他大神...

Android 自定义View

chituhuan chituhuan

05-17 549

Android 自定义View一 简单的自定义ViewAndroid View 的绘制流程主要有 onMeasure, onLayout, onDraw. UI 内容的绘制主要在onDraw 中完成。...

Android自定义view之measure、layout、draw三大流程

zuguorui zuguorui

04-13 4567

自定义view之view显示流程 一个view要显示出来,需要经过测量、布局和绘制这三个过程,本章就这三个流程详细探讨一下。View的三大流程具体分析起来比较复杂,本文不会从根源详细地分析,但是可...

Android自定义View 一<最简单的自定义View>

qq_36209474 qq_36209474

03-19 3629

为什么要自定义Viewandroid提供了很多控件供我们使用 但有些功能是系统所提供的实现不 了的 这时候我们就需要自定义一个View来实现我们所需要的效果. 在Android中所有的控件都直...

Android自定义View绘制流程小结

wjw190077 wjw190077

01-24 999

总之一句话,当系统控件满足不了我们的需求时,就需要自定义View来实现,足以表达自定义有多么强大! 通过网上资料和结合自己实践,这篇文章主要用来理解绘制流程的一个具体过程的,绘制流程的起始都是在Vi...

Android自定义View实战】之你应该明白的事儿

u010785585 u010785585

10-24 3464

在Android的实际开发中,我们Android系统本身已经给我们提供了很丰富的UI以及各种实用的控件,例如TextView,Button,ImageView等。用这些基础控件已经能够实现非常优美的界...

手把手教你写一个完整的自定义View

carson_ho carson_ho

03-14 2.9万

前言 自定义View是Android开发者必须了解的基础 今天,我将手把手教你写一个自定义View,并理清自定义View所有应该的注意点 阅读本文前,请先阅读我写的一系列自定义View文章 ...

Android 自定义View (一)

lmj623565791 lmj623565791

04-21 40.4万

很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章。先总结下自定义View的步骤...

Android自定义view详解

pengpenggxp pengpenggxp

07-11 6358

对于我这样一个Android初级开发者来说,自定义View一直是一个遥不可及的东西,每次看到别人做的特别漂亮的控件,自己心里那个痒痒啊,可是又生性懒惰,自己不肯努力去看书,只能望而兴叹,每次做需求用到...

文章热词

android 运行时 闪退 android 扫描识别边框 android dot 指示器 android商品低价提醒 android返回快捷键

相关热词

android和 android】 android与 android框 android栈

自定义仪表盘控件(源码中已经改成了自己绘制表盘)

lqc1992 lqc1992

08-09 4598

新的任务又来了,这次需要实现一个仪表盘的自定义控件,自定义控件一不常写就手生,这次又巩固下,并且学了一些新知识。https://developer.android.com/training/custo...

Android自定义View的三种实现方式

luckrr luckrr

07-07 227

参考别人的文章,简明易懂,留个笔记  参考原文链接 在毕设项目中多处用到自定义控件,一直打算总结一下自定义控件的实现方式,今天就来总结一下吧。在此之前学习了郭霖大神博客上面关于自定义View的几...

自定义View Layout过程 - 最易懂的自定义View原理系列(3)

carson_ho carson_ho

02-20 1.4万

前言 自定义View是Android开发者必须了解的基础 网上有大量关于自定义View原理的文章,但存在一些问题:内容不全、思路不清晰、无源码分析、简单问题复杂化 等 今天,我将全面总结自定义V...

自定义view中onMeasure、onLayout、onDraw、onFinishInflate、onSizeChanged方法调用时机

anhenzhufeng anhenzhufeng

06-06 2409

一般自定义view或viewGroup基本上都会去实现onMeasure、onLayout、onDraw方法,还有另外两个方法是onFinishInflate和onSizeChanged。 on...

Android动态创建View

wenweidev wenweidev

09-07 1026

代码 View view = new View(context); LinearLayout.LayoutParams params = new LinearLayo...

自定义View基础 - 最易懂的自定义View原理系列(1)

carson_ho carson_ho

02-20 1.7万

前言 自定义View原理是Android开发者必须了解的基础; 在了解自定义View之前,你需要有一定的知识储备; 本文将全面解析关于自定义View中的所有知识基础。 目录1. View的分类视图Vi...

自定义View Measure过程 - 最易懂的自定义View原理系列(2)

carson_ho carson_ho

02-20 1.6万

前言 自定义View是Android开发者必须了解的基础 网上有大量关于自定义View原理的文章,但存在一些问题:内容不全、思路不清晰、无源码分析、简单问题复杂化 等 今天,我将全面总结自定义Vi...

Android自定义View注意事项

myth13141314 myth13141314

08-06 165

自定义View的分类 继承View重写onDraw方法 主要用于实现不规则的效果,即这种效果不方便通过布局的组合方式来实现。相当于就是得自己“画”了。采用这种方式需要自己支持wrap_cont...

Android自定义View-自定义组件

yilei0033 yilei0033

03-05 136

Android自定义组件 android自定义组件一般有三种实现方式: 一、组合控件:组合控件,顾名思义就是将一些小的控件组合起来形成一个新的控件,这些小的控件多是系统自带的控件。 二、自绘控件:...

Android 自定义View(一)

qq_15192113 qq_15192113

05-31 202

Android自定义View

Android自定义View入门---自定义一个TextView

jsonnan jsonnan

06-28 1290

自定义一个TextView本篇作为入门级介绍,以自定义TextView为案例,介绍一下自定义View的流程。自定义View玩的比较溜的小伙伴们可以略过。 简介 自定义View的类型 自定义View的套...

android 中的绘制类Paint 画笔,Canvas 画布,Bitmap 类和BitmapFactory及自定义属性

Dr_abandon Dr_abandon

11-23 2592

常用的绘图类是Paint 画笔,Canvas 画布,Bitmap 类和BitmapFactoryPaint类Paint类代表画笔,用来描述图形的颜色和风格,如线宽,颜色,透明度,和填充效果等信 息,...

Android自定义View的初步总结

yuminfeng728 yuminfeng728

06-08 4109

概述在开发过程中,经常会遇到系统中提供的控件无法满足产品的设计需求,这时可能就需要考虑使用自定义的View来实现产品的设计细节了。对于自定义View,可以分为两种,一种是自定义控件(继承View),另...

自定义控件玩套路以及canvas StaticLayout的使用

qq_28195645 qq_28195645

05-18 7479

自定义控件玩套路以及canvas StaticLayout的使用

Android自定义View总结(一)基础知识与实例

chen_lian_ chen_lian_

05-20 1122

Android中,View不属于四大组件,但它甚至比Receiver和Provider都要重要。 Android提供了许多基础的控件,但远远不能满足我们的需要,很多时候我们根据需求进行新控件的定义,这...

Android自定义View的用法总结

bigconvience bigconvience

05-23 4601

本文参考了:http://greenrobot.me/devpost/android-custom-layout/ Android SDK中提供了很多UI组件,如RelativeLayout, L...

下载

android 自定义View

12-13

android 自定义View android 自定义View

下载

自定义view

05-18

android自定义view,自定义属性的使用

下载

Android自定义View

03-20

Android中自定义View操作Android中自定义View操作Android中自定义View操作

Android 自定义view完全解析--带你通透了解自定义view

u011200604 u011200604

02-22 8767

参考转自郭霖博客带你一步步深入了解View系列 Android LayoutInflater原理分析 相信接触Android久一点的朋友对于LayoutInflater...

Android应用自定义View绘制方法手册

yanbober yanbober

04-04 3万

这篇迟迟难产的文章算是对2015前半年的一个交代吧,那时候有一哥们要求来一发Android Canvas相关总结,这哥们还打赏了,实在不好意思,可是这事一放就给放忘了,最近群里小伙伴催着说没更新博客,...

Android自定义View(二、深入解析自定义属性)

u010163442 u010163442

05-21 2.5万

转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51454685 本文出自:【openXu的博客】 [TOC] 在上一篇博...

简单说说Android自定义view学习推荐的方式

wingichoy wingichoy

01-08 9279

这几天比较受关注,挺开心的,嘿嘿。 这里给大家总结一下学习自定义view的一些技巧。 1.首先 去看看鸿洋神的博客 Android 自定义view(1). 鸿洋神的入门教程讲的很详细。再次膜拜...

自定义View自定义属性及引用

bobo8945510 bobo8945510

11-17 5510

学习导航….后续添加,自定义view不是一章能说清的。本章讲解: 自定义视图,我们需要做哪些准备!对于一些中级的开发者来说就要接触到自定义视图,由于Android自带的视图无法满足自己需求,又或者美观...

自定义View不能显示?来看看Studio怎么说!

github_37586705 github_37586705

10-16 942

android自定义view不显示

自定义View(三)---自定义View整个流程的梳理与总结

cjm2484836553 cjm2484836553

04-30 1280

转载请注明出处:From李诗雨—http://blog.csdn.net/cjm2484836553/article/details/71024436 不诗意的女程序猿不是好厨师~ 在自定义Vi...

Android自定义View高级(一)-分类与流程

u014005316 u014005316

01-19 1323

一.自定义View绘制流程二.自定义View分类 自定义ViewGroup 自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件,大多继承自ViewGroup或各种Layou...

Android-自定义View使用

githan githan

10-25 296

Android所有的控件都继承至View,所以我们可以通过继承View来实现自己想要的控件,具体代码如下:1,创建自定义View 类import android.content.Context; im...

Android - 自定义View不显示

u012246458 u012246458

12-06 3740

说明: 自定义了一个LinearLayout,显示不出来 原因是必须有 public ManDaoH5View(Context context, AttributeSet attrs) { 这个方法...

下载

Android自定义View之进度条Demo

10-23

Android自定义View之进度条Demo,Android自定义View之进度条Demo

自定义view-二,使用枚举

qq_15771061 qq_15771061

04-05 979

在自定义View中添加enum类型,类似android 中的match_parent和wrap_content

下载

android自定义view(一)——attire 使用

06-04

android自定义view(一)——attire 使用

Android使用handler和Runnable结合,自定义View更新UI的Demo

canghai1129 canghai1129

04-12 2449

前三周在修改android4.2锁屏UI,刚做android好多知识不会啊,里面有个动画效果是一个jian...

下载

自定义view解决android文本排版和换行问题

03-23

自定义view解决android文本排版和换行问题自定义view解决android文本排版和换行问题自定义view解决android文本排版和换行问题自定义view解决android文本排版和换行问题自定义view解决android文本排...

下载

android自定义view:十字按钮(用于智能家电APP)

12-02

本十字按钮可用于智能家电app,通过设置listener就可以监听四个方向的点击事件,同时其button的反应模式如系统给的button一致。在代码中也给出了另外五个普通按钮进行与十字按钮进行效果对比

自定义View——坑、技巧、调优

sinat_15877283 sinat_15877283

04-04 2620

相信有创建过“自定义View”经验的众多的开发者朋友当中有相当一部分人猿友是直接copy网上的一些代码拿来用,结果往往不尽如人意, 碰到bug或者是需求发生变化时往往手忙脚乱,android自定义Vi...

安卓自定义View进阶 - 贝塞尔曲线

u013831257 u013831257

04-29 1.4万

在上一篇文章Path之基本图形中我们了解了Path的基本使用方法,本次了解Path中非常非常非常重要的内容-贝塞尔曲线。...

Android自定义View的官方套路

yissan yissan

04-12 1.7万

概述Android已经为我们提供了大量的View供我们使用,但是可能有时候这些组件不能满足我们的需求,这时候就需要自定义控件了。自定义控件对于初学者总是感觉是一种复杂的技术。因为里面涉及到的知识点会比...

Android 自定义View之绘图

moira33 moira33

01-19 2074

【Android 自定义View之绘图】 Android 自定义View之绘图 基础图形的绘制 一Paint与Canvas Paint Paint的基本设置函数 setAntiAliastrue...

自定义View之基础篇

showdy showdy

12-10 579

Android APP屏幕区域划分: 1.状态栏区域: //获取屏幕区域的宽高等尺寸获取 DisplayMetrics metrics = new DisplayMetrics(); ...

没有更多推荐了,返回首页

个人资料

峥嵘life

已关注

原创

343

粉丝

617

喜欢

1035

评论

369

等级:

访问:

88万+

积分:

1万+

排名:

1874

勋章:

持之以恒

授予每个自然月内发布4篇或4篇以上原创或翻译IT博文的用户。不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累!

最新文章

  • Android 多线程之HandlerThread 详解
  • java判断一个字节数组在另一个字节数组的位置
  • 阿里巴巴的FastJson数据解析介绍
  • 讯飞语音识别和唤醒开发示例
  • 使用adb logcat命令显示Android设备上的Log日志

个人分类

  • android259篇
  • C语言基础6篇
  • java105篇
  • java集合4篇
  • java IO8篇
  • 数据库2篇
  • 人生感言13篇
  • Socket编程2篇
  • 面试13篇
  • java多线程6篇
  • Android文件资源使用11篇
  • UI42篇
  • Andr图形和动画7篇
  • Android多媒体3篇
  • 工具类13篇
  • android数据7篇
  • 消息处理机制3篇
  • 广播接收者1篇
  • 安卓服务2篇
  • Android网络25篇
  • 传感器1篇
  • 框架模式2篇
  • 插件4篇
  • 网络框架17篇
  • 高级控件13篇
  • xutils4篇
  • Fragment4篇
  • Vitamio1篇
  • 百度地图开发2篇
  • 设计模式25篇
  • ps17篇
  • webservice3篇
  • 报错情况3篇
  • dicom图像文件6篇
  • kotlin15篇

展开

归档

  • 2018年9月 3篇
  • 2018年8月 1篇
  • 2018年7月 5篇
  • 2018年6月 6篇
  • 2018年5月 5篇
  • 2018年4月 15篇
  • 2018年3月 12篇
  • 2018年2月 7篇
  • 2018年1月 1篇
  • 2017年12月 3篇
  • 2017年11月 7篇
  • 2017年10月 8篇
  • 2017年9月 7篇
  • 2017年8月 5篇
  • 2017年7月 20篇
  • 2017年6月 10篇
  • 2017年5月 14篇
  • 2017年4月 15篇
  • 2017年3月 23篇
  • 2017年2月 22篇
  • 2017年1月 9篇
  • 2016年12月 45篇
  • 2016年11月 26篇
  • 2016年10月 21篇
  • 2016年9月 45篇
  • 2016年8月 16篇

展开

热门文章

  • javaj经典程序编程50题

    阅读量:48214

  • java多线程的常见例子

    阅读量:32260

  • eclipse快捷键的设置和使用

    阅读量:30320

  • Android显示时间和日期的控件的使用总结

    阅读量:22081

  • Java IO流经典练习题

    阅读量:21601

最新评论

  • Android 多线程之Handl...

    headw:写的这是什么玩意。。。。。

  • Android一次申请多个动态权限

    weixin_39657438:转载了 楼主写的很清晰

  • 使用cmd根据WSDL网址生成ja...

    qq_41913924:[reply]Daisy_ljq[/reply] 在你发布webService的时候设置

  • Android网络定位或GPS定位

    weixin_40413165:大神,我按照您的程序写出,无法获取经纬度信息啊,就是什么都不显示,请教请教

  • 走穿java23种设计模式-3抽象...

    MirabelleZWH:谢谢分享

联系我们

客服

请扫描二维码联系客服

[email protected]

400-660-0108

QQ客服 客服论坛

关于招聘广告服务 网站地图

©2018 CSDN版权所有 京ICP证09002463号

百度提供搜索支持

经营性网站备案信息

网络110报警服务

中国互联网举报中心

北京互联网违法和不良信息举报中心

CSDN APP

  • 点赞取消点赞

    5

  • 评论

     

  • 目录
    1. 一View 的基本概念
      1. 一View的理解
      2. 二IDs
      3. 三获取View的位置信息
    2. 二View创建概述
      1. 一Creation创建流程
        1. 调用构造器
      2. 二Layout布局流程
        1. onMeasureint w int h 确定View和它所有的子View要求的尺寸时调用
        2. onLayoutboolean change int left int topint right int button 当这个View为其所有的子View指派一个尺寸和位置时调用
        3. onSizeChangedint w int h int oldw int oldh 当这个View的尺寸改变后调用
      3. 四Drawing绘制过程自定义View的重点方法哦
      4. 五Event事件流程
        1. onKeyDownint KeyEvent当一个新的键按下时
        2. onKeyUpint KeyEvent 当一个键弹起时
        3. onTrackballEventMotionEvent当滚迹球事件发生时
        4. onTouchEventMotionEvent当一个触摸屏事件发生时
      5. 五Focus焦点流程
        1. onFocusChangedboolean intRect 当View得到和失去焦点时调用
        2. onWindowFocusChangedboolean 当Window包含的View得到或失去焦点时调用
    3. 三定制View
      1. 一扩展View或者View的子类
      2. 二 必须实现其中一个构造方法一般都是实现两个
      3. 三重写onDrawcanvas方法进行绘制整个涉及到绘制任意的图像比如画线画圆画矩形等等
      4. 四如需调整大小重写onMesure默认是全屏的
      5. 五如需样式在xml中布置自定义属性
    4. 四测量布局MeasureSpec
      1. 一下面是各个模式的标志位表示
      2. 二这样表示一个View大小是很方便的我们来看下面的方法
        1. 下面是网友对MeasureSpec的一个理解
    5. 五常用的绘图类
      1. 一Paint类
        1. 常用方法paint
      2. 二Bitmap类
        1. compressBitmapCompressFormat format int quality OutputStream stream
        2. createBitmapBitmap source int x int y int width int height Matrix m boolean filter
        3. createBitmapBitmap source int x int y int width int height
      3. 三BitmapFactory类
        1. decodeFileString pathName 用于从给定的路径所指定的文件中解析创建Bitmap对象
      4. 四Canvas类
      5. 绘制几何图形
        1. 绘制文本
        2. 绘制路径
    6. 六自定义属性这个使用起来相对比较麻烦一般不用
      1. 一attsxml的文件
      2. 二自定义属性格式和意义
      3. 三在布局文件中使用自定义属性
      4. 四然后我们在自定义View中实现带AttributeSet属性的构造方法并且获取自定义值
    7. 七组合控件
      1. 一创建文件title_textxml
      2. 二接下来创建一个TitleView继承自FrameLayout代码如下所示
    8. 八绘制图片返回的都是一个Bitmap对象
      1. 一drawBitmapBitmap bitmap Rect src RectF dst Paint paint
      2. 二drawBitmapBitmap bitmap float left float top Paint paint
      3. 三drawBitmapBitmap bitmap Rect src Rect dst Paint paint
    9. 下面是一些程序的示例
    10. 九一个绘制简单图形图像的示例
      1. 一创建MyView继承View
      2. 二调用
    11. 十简易画板的实现
    12. 十一一个自定义的进度框框的显示
      1. 一自定义View的代码
      2. 二调用类的代码
      3. 三Xml文件
    13. 十二Bitmap对象的操作压缩保存和显示
      1. 一xml布局文件设计
      2. 二java代码

     

  • 收藏
  • 手机看
  • 上一篇
  • 下一篇
  • 更多
    • 上一篇
    • 下一篇

 

 

不良信息举报

 

举报内容:

Android自定义View使用总结

举报原因:

色情政治抄袭广告招聘骂人其他

原文地址:

 

原因补充:

最多只允许输入30个字

 

你可能感兴趣的:(Android)