美文网首页
Android绘图机制和处理技巧

Android绘图机制和处理技巧

作者: 14cat | 来源:发表于2016-08-02 22:25 被阅读301次

    前言

    • Android群英传读书笔记

    目录

    Android绘图机制与处理技巧.png

    Android屏幕相关知识

    • 了解一些基础名词和参数信息

    屏幕尺寸信息

    屏幕参数

    • 屏幕大小:指屏幕对角线的长度,通常使用“寸”来度量,如4.7寸、5.5寸手机等
    • 分辨率:手机屏幕像素点的个数,720×1280就是指宽有720个像素点,高有1280个像素点
    • PPI:每英寸像素,又名DPI,由对角线的像素点数除以屏幕的大小得到的

    系统屏幕密度

    密度 密度值 分辨率
    ldpi 120 240×320
    mdpi 160 320×480
    hdpi 240 480×800
    xhdpi 320 720×1280
    xxhdpi 480 1080×1920

    独立像素密度dp

    Android系统使用mdpi即密度值为160的屏幕作为标准,在这个屏幕上1px = 1dp,其他屏幕可以进行比例换算,例如同样是100dp的长度,在mdpi中为100px,而hdpi中为150px。也就是说在mdpi中1dp = 1px,而hdpi中1dp = 1.5px,在xdpi中1dp = 2px,在xxhpi中1dp = 3px

    各分辨率换算比率
    ldpi :mdpi :hdpi :xhdpi :xxhdpi = 3:4:6:8:12

    单位换算

    • 这里的换算封装成工具类以便以后使用
    • 核心就是从DisplayMetrics显示度量类中获取信息
    • 这里我顺便添加了获得屏幕宽度的方法
    public class DisplayUtils {
    
        /**
         * 获得屏幕宽度(像素)
         *
         * @param activity
         * @return
         */
        public static int getDisplayWidth(Activity activity) {
            DisplayMetrics metric = new DisplayMetrics();
            activity.getWindowManager().getDefaultDisplay().getMetrics(metric);
            int width = metric.widthPixels;     // 屏幕宽度(像素)
            return width;
        }
    
        /**
         * 获得屏幕高度(像素)
         *
         * @param activity
         * @return
         */
        public static int getDisplayHeight(Activity activity) {
            DisplayMetrics metric = new DisplayMetrics();
            activity.getWindowManager().getDefaultDisplay().getMetrics(metric);
            int height = metric.heightPixels;     // 屏幕高度(像素)
            return height;
        }
    
    
        /**
         * 将px值转换为dip或dp值,保证尺寸大小不变
         *
         * @param context 通过上下文获得显示参数中的屏幕密度
         * @param pxValue 需要转换的px值
         * @return
         */
        public static int px2dip(Context context, float pxValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (pxValue / scale + 0.5f);
        }
    
    
        /**
         * 将dip或dp值转换为px值,保证尺寸大小不变
         *
         * @param context  通过上下文获得显示参数中的屏幕密度
         * @param dipValue 需要转换的dp值
         * @return
         */
        public static int dip2px(Context context, float dipValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (dipValue * scale + 0.5f);
        }
    
    
        /**
         * 将px值转换为sp值,保证文字大小不变
         *
         * @param context 通过上下文获得显示参数中的屏幕密度
         * @param pxValue 需要转换的px值
         * @return
         */
        public static int px2sp(Context context, float pxValue) {
            final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
            return (int) (pxValue / fontScale + 0.5f);
        }
    
    
        /**
         * 将sp值转换为px值,保证文字大小不变
         *
         * @param context 通过上下文获得显示参数中的屏幕密度
         * @param spValue 需要转换的sp值
         * @return
         */
        public static int sp2px(Context context, float spValue) {
            final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
            return (int) (spValue * fontScale + 0.5f);
        }
    }
    

    Android绘图技巧

    2D绘图技巧

    • 系统通过Canvas画布对象来提供绘图方法,它提供了各种绘图API
    API 绘制(6)
    drawPoint()
    drawLine() 线
    drawsLine() 多条线
    drawRect() 矩形
    drawRoundRect() 圆角矩形
    drawVertices() 多边形
    drawArc() 弧、扇
    drawCircle()
    drawOval() 椭圆
    drawText() 绘制文本
    drawPosText() 在指定位置绘制文本
    drawPath() 绘制路径
    drawBitmap() 绘制Bitmap(加载)
    API 设置属性
    setAntiAlias() 设置画笔锯齿效果
    setColor() 设置画笔颜色
    setARGB() 设置画笔A,R,G,B值
    setAlpha() 设置画笔Alpha值
    setTextSize() 设置字体尺寸
    setStyle() 设置画笔风格(空心或实心)
    setStrokeWidth() 设置空心边框的宽度
    reset() 重置

    绘制的实例
    http://blog.csdn.net/rhljiayou/article/details/7212620

    • 需要注意其中画弧和扇形,本质是画一个矩形,以矩形的中心为弧或扇的中心点,以矩形的中心为角度的坐标原点绘制

    Android XML绘图

    Bitmap

    • 将图片直接转换为Bitmap
    <?xml version="1.0" encoding="utf-8"?>
    <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
        android:src="@mipmap/ic_launcher"/>
    

    Shape

    • 绘制各种形状,省去了canvas和paint的步骤
    <?xml version="1.0" encoding="utf-8"?>
    <shape    
        xmlns:android="http://schemas.android.com/apk/res/android"    
        android:shape=["rectangle" | "oval" | "line" | "ring"] >    
        <corners        //当shape为rectangle时使用
            android:radius="integer"        //半径值会被后面的单个半径属性覆盖,默认为1dp
            android:topLeftRadius="integer"        
            android:topRightRadius="integer"        
            android:bottomLeftRadius="integer"        
            android:bottomRightRadius="integer" />    
        <gradient       //渐变
            android:angle="integer"        
            android:centerX="integer"        
            android:centerY="integer"        
            android:centerColor="integer"        
            android:endColor="color"        
            android:gradientRadius="integer"        
            android:startColor="color"        
            android:type=["linear" | "radial" | "sweep"]        
            android:useLevel=["true" | "false"] />    
        <padding        //内边距
            android:left="integer"        
            android:top="integer"        
            android:right="integer"        
            android:bottom="integer" />    
        <size           //指定大小,一般用在imageview配合scaleType属性使用
            android:width="integer"        
            android:height="integer" />    
        <solid          //填充颜色
            android:color="color" />    
        <stroke         //边框
            android:width="integer"        
            android:color="color"        
            android:dashWidth="integer"        
            android:dashGap="integer" />
    </shape>
    

    Layer 层

    
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@drawable/ic_launcher" />
        <item android:drawable="@drawable/ic_launcher" 
                   android:left="10.0dp"
                   android:top="10.0dp"
                   android:right="10.0dp"
                   android:bottom="10.0dp"/>
        ......
    </layer-list>
    

    Selector 选择器

    • Fragment配合RadioGroup实现点击切换内容时RadioGroup的子项就是用选择器作为View的触摸反馈,不过我更喜欢FragmentTabHost做为下方选项卡(跑题了。。。)
    <?xml version="1.0" encoding="utf-8" ?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- 默认时的背景图片-->
        <item android:drawable="@drawable/X1"/>
        <!-- 没有焦点时的背景图片 -->
        <item android:drawable="@drawable/X2" android:state_window_focused="false"/>
        <!-- 非触摸模式下获得焦点并单击时的背景图片 -->
        <item android:drawable="@drawable/X3" android:state_focused="true" android:state_pressed="true"/>
        <!-- 触摸模式下单击时的背景图片-->
        <item android:drawable="@drawable/X4" android:state_focused="false" android:state_pressed="true"/>
        <!--选中时的图片背景-->
        <item android:drawable="@drawable/X5" android:state_selected="true"/>
        <!--获得焦点时的图片背景-->
        <item android:drawable="@drawable/X6" android:state_focused="true"/>
    </selector>
    
    

    Android绘图技巧

    • 简化,优化绘图操作

    Canvas

    API 作用
    Canvas.save() 保存画布(类似PS中的图层保存)
    Canvas.restore() 合并画布(类似PS中的合并图层)
    Canvas.translate() 画布所在坐标系平移
    Canvas.rotate() 画布所在坐标系旋转

    Layer 层

    • 类似于PS中图层的概念
    • 基于栈的结构进行管理的
    API 作用
    saveLayer() 将图层入栈
    saveLayerAlpha() 将图层入栈
    restore() 将图层出栈
    restoreCount() 将图层出栈
    • 入栈时,后面所有的操作都会发生在这个图层中
    • 出栈时,则会把图像绘制到上层Canvas上
    @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            canvas.drawColor(Color.WHITE);
            p.setColor(Color.BLUE);
            canvas.drawCircle(150, 150, 100, p);
    
            // 图一
            canvas.saveLayerAlpha(0, 0, 400, 400, 127, LAYER_TYPE_NONE);
            // 图二
    //        canvas.saveLayerAlpha(0, 0, 400, 400, 255, LAYER_TYPE_NONE);
            p.setColor(Color.RED);
            canvas.drawCircle(200, 200, 100, p);
            canvas.restore();
        }
    
    
    图一,透明度为127时,为半透明状态 图二,透明度设置为255时,完全不透明

    Android图像处理技巧

    • Android对于图片的处理,最常用使用到的数据结构就是位图--Bitmap,它包含一张图片的所有数据
    • 整个图片都是有点阵和颜色组成的
    • 点阵就是一个包含像素的矩阵,每个元素对应者图片的一个像素

    色彩矩阵分析

    • 在色彩处理中通常用以下三个角度描绘一个图像
    • 色调--物体传播的颜色
    • 饱和度--颜色的纯度,从0(灰)到100%(饱和)来进行描述
    • 亮度--颜色的相对明暗程度
    • 在Android中系统使用颜色矩阵ColorMatrix来处理这个色彩效果

    // ---- 施工中(8月2日--6日) ----


    SurfaceView的使用

    • SurfaceView是为了解决View中执行操作逻辑太多出现卡顿的情况

    SurfaceView和View的区别

    • View主要适用于主动更新的情况下,而SurfaceView主要适用于被动更新,例如频繁的刷新
    • View在主线程中对画面进行刷新,而SurfaceView通常会通过一个子线程来进行页面的刷新
    • View在绘图时没有使用双缓冲机制,而SurfaceView在底层实现机制中已经实现了双缓冲机制

    SurfaceView的使用

    • 创建SurfaceView
      • 自定义SurfaceView继承SurfaceView
      • 实现SurfaceHolder.Callback接口,并实现对应的三个方法
      • 实现Runnable接口,实现run()方法
     @Override
        public void surfaceCreated(SurfaceHolder surfaceHolder) {
    
        }
        @Override
        public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
    
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
    
        }
    
        @Override
        public void run() {
    
        }
    
    • 初始化SurfaceView
    private SurfaceHolder mHolder;
    private Canvas mCanvas;
    private boolean mIsDrawing;
    
    private void init() {    
         mHolder = getHolder(); 
         mHolder.addCallback(this);
    }
    
    • 使用SurfaceView
    API 作用
    lockCanvas() 获得当前Canvas对象
    drawColor() 清屏
    public class SurfaceViewDemo extends SurfaceView implements Runnable, SurfaceHolder.Callback {
    
        private SurfaceHolder mHolder;
        private Canvas mCanvas;
        private boolean mIsDrawing;         // 子线程标志位
    
        public SurfaceViewDemo(Context context) {
            super(context);
            initView();
        }
    
        private void initView() {
            mHolder = getHolder();
            mHolder.addCallback(this);
    
            setFocusable(true);
            setFocusableInTouchMode(true);
            this.setKeepScreenOn(true);
            // mHolder.setFormat(PixelFormat.OPAQUE);
        }
    
    
        @Override
        public void surfaceCreated(SurfaceHolder surfaceHolder) {
            mIsDrawing = true;
            new Thread(this).start();
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
    
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
            mIsDrawing = false;
        }
    
        @Override
        public void run() {
            while (mIsDrawing) {
                draws();
            }
        }
    
        public void draws() {
            try {
                mCanvas = mHolder.lockCanvas();
            } catch (Exception e) {
                
            } finally {
                if (mCanvas != null) {
                    mHolder.unlockCanvasAndPost(mCanvas);
                }
            }
        }
    }
    

    SurfaceView实例

    1. 正选曲线

    @Override
        public void run() {
            while (mIsDrawing) {
                draws();
                x += 1;
                y = (int) (100 * Math.sin(x * 2 * Math.PI/180) + 400);
                mPath.lineTo(x, y);
            }
        }
    
        private void draws() {
            try {
                mCanvas = mHolder.lockCanvas();
                // Surface背景
                mCanvas.drawColor(Color.WHITE);
                mCanvas.drawPath(mPath, mPaint);
            } catch (Exception e) {
    
            } finally {
                if (mCanvas != null) {
                    mHolder.unlockCanvasAndPost(mCanvas);
                }
            }
        }
    
    绘制正弦曲线

    2. 绘图板

    private void draws() {
            try {
                mCanvas = mHolder.lockCanvas();
                // Surface背景
                mCanvas.drawColor(Color.WHITE);
                mCanvas.drawPath(mPath, mPaint);
            } catch (Exception e) {
    
            } finally {
                if (mCanvas != null) {
                    mHolder.unlockCanvasAndPost(mCanvas);
                }
            }
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int x = (int) event.getX();
            int y = (int) event.getY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mPath.moveTo(x,y);
                    break;
                case MotionEvent.ACTION_MOVE:
                    mPath.lineTo(x, y);
                    break;
                case MotionEvent.ACTION_UP:
                    break;
            }
            return true;
        }
    
    
    画笔粗细没调。。

    相关文章

      网友评论

          本文标题:Android绘图机制和处理技巧

          本文链接:https://www.haomeiwen.com/subject/fusfsttx.html