android之绘图——Canvas,bitmap,Paint的理解

     经常要和绘图打交道,总是用Canvas,bitmap,Paint,但是对它们的理解总是模糊,这里作下总结,加深对绘图的理解。

    查询Canvas的官方解释:Canvas用来实现对绘图的操作。你需要4个组件来实现绘图的操作:

            a).bitmap,保存着像素

            b).canvas.执行画图的命令(向bitmap执行写操作)

            c).drawing primtive(e.g.Rect,Path,text,bitmap).绘图的原始内容。

            d).paint.(用来描述绘图时的使用的颜色和风格)

            这些解释都很抽象,下面我来说下对它们的形象的理解,说明这4个基本控件,这样加深印象:

     我们就用现实中的画图来比拟对android中绘图的理解:

            a)bitmap.我们绘图肯定需要一块画布,这个画布承载内容用来表现所要显示的图。它有大小,你可以在上面涂颜料进行绘图,或什么都不涂。

            b).canvas.画布本身不会被绘制,只有当画家去操作画笔,画布才会绘制上图画。这里的canvas就像相当于画家执行画图的操作,绘图的过程。

            c).drawing primitive.画家绘图需要参照物,比如你绘图,肯定是有个目标,比如绘制一个字体,一个圆圈,一个矩形(Rect),另一幅图(bitmap)。

            d).paint.绘图需要画笔,paint就相当于这个画笔,你可以定制颜色,粗细。

      下面了解Canvas,bitmap,paint一些常用的方法:

           Bitmap

           .获取bitmap方法

            读取InputStream得到位图  

InputStream is = getResources().openRawResource(R.drawable.ic_launcher);
BitmapDrawable bd = new BitmapDrawable(is);
Bitmap bp = bd.getBitmap();
          解码位图来获取位图,如果你在解析大图片遇到OOM问题,不妨尝试这个方法,这个方法利用JNI调用来解析bitmap,减轻了java层空间的压力。

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
          位图的创建,你可以利用下面方法来创建一个bitmap
matrix 指定对bitmap像素的操作
createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter);
//width,height用来指定创建图片的大小,config用来指定创建图片的质量,
其中config有共有4个标准:	ALPHA_8,ARGB_4444,ARGB_8888,RBG_565,这些标准分别定义图片像素存储的情况,RBG_565是比较常用的,
ARBG_8888指定的图片质量最高
createBitmap(int width, int height, Bitmap.Config config);
createBitmap(Bitmap source, int x, int y, int width, int height);

         Canvas

         Canvas();创建一个空画布,它必须绑定bitmap才有效,一般以bitmap来创建一个bitmap的操作,当canvas进行绘图,他绘制的内容都绘在bitmap上。

         常见的Canvas绘制使用场合:

          a.自定义View时绘制

@Override
	OnDraw(Canvas canvas){
		//利用canvas执行绘图操作
	}

          b.利用surfaceView时绘制       
SurfaceHoler holder = SurfaceView.getHolder();
	Canvas canvas = holder.lockCanvas();
	//利用canvas进行绘图操作
	
	holder.unlockCanvasAndPost(canvas);//对canvas解锁,并更新

         绘制图形的方法:

         drawCircle(float cx, float cy, float radius, Paint paint);//绘制圆圈

         drawLine(float startX, float startY, float stopX, float stopY, Paint paint)//绘制直线

       裁剪绘图区域

       clipXXX()方法类

       从当前区域里裁剪一块新的画图区域,裁剪后的新区域即为绘图的新区域。

      save(),restore()方法

      在绘图时,我们经常会用到canvas类的save(), restore()方法,它们到底是怎么用的呢?

      这里有篇详细讲解这两个方法的文章,和大家分享:

      https://developer.mozilla.org/en/Canvas_tutorial/Transformations

      *save,用来保存Canvas状态,调用之后,你可以调用canvas对画布进行平移、缩放、裁剪等操作。

      *restore.用来恢复Canvas之前保存的状态,这样不仅能够复用先前保存的状态,节约资源,另一方面避免对影响图片后续的绘制。

     Paint

      Paint(),//创建画笔

      setColor(int color)//设置画笔的颜色

      setAlpha(int a)//设置图片透明度

      setDither(boolean dither)//设置画笔是否反锯齿

      setStrokeWidth(float width)//设置画笔的宽度

     小例子学习

        做一小例子温习巩固绘图的操作,要求实现仿卷帘拉起效果。

        先简述一下情景:。首先,手机上显示一张完整的图片,图片顶端固定不变。然后,手指在图片上开始滑动,图片的底部随着手指位置而不断变化。你看到的效果是图片的从顶端显示你手指滑动的所在位置。所以,你看到的总是不完整的图片。先上效果,这样大家更好理解。

          

       为了实现上述效果的复用,我们可以自定义一个view,可以设置背景图片,提示的箭头的图片以及图片顶端保留空间大小。

    1.自定义MovingView.java,实现上述功能   

package com.lawrence;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class MovingView extends View {
	
	private Bitmap backgroundBitmap;
	private Bitmap handleBitmap;
	private Bitmap showBitmap;
	private int backgroundWidth;
	private int backgroundHeight;
	private int handleWidth;
	private int handleHeight;
	private int currentY;
	private int showHeight;
	private int topSpace;
	private Canvas mCanvas;
	private Rect backgroundSrc;
	
	public MovingView(Context context, AttributeSet attrs) {
		super(context, attrs);
		
		TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Movingview);
		//获取背景图片
		Drawable backgroundDrawable = a.getDrawable(R.styleable.Movingview_movingbackground);
		//获取拉手图片
		Drawable handleDrawable = a.getDrawable(R.styleable.Movingview_handlebackground);
		//获取顶端保留的高度大小。这个高度用做滑动到顶部保留的最小高度。
		topSpace = (int) a.getDimension(R.styleable.Movingview_extraspace, 10);
		backgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();
		handleBitmap = ((BitmapDrawable) handleDrawable).getBitmap();
		//获取图片高宽
		backgroundWidth = backgroundBitmap.getWidth();
		backgroundHeight = backgroundBitmap.getHeight();
		handleWidth = handleBitmap.getWidth();
		handleHeight = handleBitmap.getHeight();
		
		//根据图片大小创建一个相同大小的bitmap
		showBitmap = Bitmap.createBitmap(backgroundWidth, backgroundHeight + (handleHeight >> 1), Config.RGB_565);
		//创建一个canvas,并绑定bitmap。
		mCanvas = new Canvas(showBitmap);
		//绘制定backgroundBitmap到showBitmap。
		mCanvas.drawBitmap(backgroundBitmap, 0, 0, null);
		//在backgroundBitmap底部的中间位置绘制拉手图片
		mCanvas.drawBitmap(handleBitmap, (backgroundWidth - handleWidth) >> 1, backgroundHeight - (handleHeight >> 1), null);
	}

	public MovingView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public MovingView(Context context) {
		super(context);
	}



	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		//设置图片的大小为此View的大小
		setMeasuredDimension(backgroundWidth, backgroundHeight + (handleHeight >> 1));
		
	}

	@Override
	protected void onDraw(Canvas canvas) {
		//更新绘制图片
		canvas.drawBitmap(showBitmap, 0, 0, null);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			
			break;
		case MotionEvent.ACTION_MOVE:
			currentY = (int) event.getY();
			showHeight = currentY;
			if(showHeight > backgroundHeight)
				showHeight = backgroundHeight;
			if(showHeight < topSpace)
				showHeight = topSpace;
			//清除图片
			mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
			//根据滑动位置确定新绘制区域
			backgroundSrc = new Rect(0, 0, backgroundWidth, showHeight);
			//绘制背景
			mCanvas.drawBitmap(backgroundBitmap, backgroundSrc, backgroundSrc, null);
			//绘制拉手
			mCanvas.drawBitmap(handleBitmap, (backgroundWidth - handleWidth) >> 1, showHeight - (handleHeight >> 1), null);
			invalidate();//更新
			break;
		case MotionEvent.ACTION_UP:
			
			break;
		}
		return true;
	}

}
          2.自定义MovingView的属性:          
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="Movingview">
        <attr name="movingbackground" format="reference"/>
        <attr name="handlebackground" format="reference"/>
        <attr name="extraspace" format="dimension"/>
    </declare-styleable>
</resources>

        3.布局文件main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:moving="http://schemas.android.com/apk/res/com.lawrence"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />
	<com.lawrence.MovingView
	    android:id="@+id/imageview"
	    android:layout_width="wrap_content"
	    android:layout_height="wrap_content"
	    moving:extraspace="30dp"
	    moving:movingbackground="@drawable/bofucur"
	    moving:handlebackground="@drawable/updownsel"
	    />
</LinearLayout>

    主Activity就不贴了,很简单,只要setcontentView(R.layout.main).


    附:Demo源码位置:http://download.csdn.net/detail/a2758963/4459566


  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值