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

来源:互联网 发布:多乐炸金花作弊软件 编辑:程序博客网 时间:2024/05/16 17:53

     经常要和绘图打交道,总是用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时绘制

@OverrideOnDraw(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();//根据图片大小创建一个相同大小的bitmapshowBitmap = 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);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//设置图片的大小为此View的大小setMeasuredDimension(backgroundWidth, backgroundHeight + (handleHeight >> 1));}@Overrideprotected void onDraw(Canvas canvas) {//更新绘制图片canvas.drawBitmap(showBitmap, 0, 0, null);}@Overridepublic 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


原创粉丝点击