Android绘图机制和处理技巧

前言

  • 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;
    }

画笔粗细没调。。
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容