Android UI绘制

屏幕适配

几个基本概念

屏幕尺寸:手机对角线的物理尺寸,1英寸=2.54cm,Android手机常见的尺寸有5寸、5.5寸、6寸等等
屏幕分辨率:手机在横向、纵向上的像素点数总和,eg:1080px X 1920px
屏幕像素密度DPI:每英寸的像素点数
dp:密度无关像素。dp最终也是转化为px,根据密度DPI来决定比例
sp:独立比例像素。sp最终也是转化为px,根据系统设置里大中小号字体来决定比例

这里写图片描述

布局匹配

  • 禁用绝对布局(AbsoluteLayout)
  • 布局文件夹
    • res/layout/main.xml 正常单面屏布局
    • res/layout-large/main.xml 大于7寸屏幕的双面屏布局,一般平板
    • res/layout-sw600dp/main.xml 大于600dp屏幕的布局
    • res/values-sw600dp-land/layouts.xml 横屏且大于600dp屏幕的布局
    • res/values-large-land/layouts.xml 横屏且大于7寸屏幕的布局

图片资源适配

  • 9png
  • 一般做一套720x1280的图片放xhdpi 或 做一套1080x1920的图片放xxhdpi
  • mipmap相对drawable加载性能会更好些

控件适配:别把控件宽高设死

  • 使用”wrap_content”、”match_parent”和”weight“来控制视图组件的宽度和高度
  • 使用padding、margin来控制控件

drawable

  • BitmapDrawable
<bitmap>
android:antialias=["true" | "false"]//抗锯齿效果
android:dither=["true" | "false"]//抖动效果
android:filter=["true" | "false"]//是否允许对位图进行滤波。当图片被压缩或者拉伸时,使用滤波可以获得平滑的外观效果
android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
                      "fill_vertical" | "center_horizontal" | "fill_horizontal" |
                      "center" | "fill" | "clip_vertical" | "clip_horizontal"]
android:tileMode=["disabled" | "clamp" | "repeat" | "mirror"]//平铺模式
  • ShapeDrawable
<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape=["rectangle" | "oval" | "line" | "ring"] >
    <corners
        android:radius="integer"
        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:usesLevel=["true" | "false"] />
    <padding
        android:left="integer"
        android:top="integer"
        android:right="integer"
        android:bottom="integer" />
    <size
        android:width="integer"
        android:height="integer" />
    <solid
        android:color="color" />
    <stroke
        android:width="integer"
        android:color="color"
        android:dashWidth="integer"
        android:dashGap="integer" />
</shape>
 - android:shape=["rectangle" | "oval" | "line" | "ring"] 矩形、椭圆、横线、圆环
     - ring圆环下的一些配置
         - android:innerRadius 圆环半径
         - android:innerRadiusRatio 内半径占整个Drawable宽度的比例
         - android:thickness 圆环的厚度
         - android:thicknessRatio 厚度占整个Drawable宽度比例
         - android:useLevel 一般都应该使用false,否则可能无法达到预期显示效果,除非它被当做LevelListDrawable来使用

 - corners 圆角
     - android:radius 四个角的半径
     - android:topLeftRadius 左上角的半径
     - android:topRightRadius
     - android:bottomLeftRadius
     - android:bottomRightRadius

 - gradient 渐变填充
     - android:angle 渐变角度
     - android:centerX android:centerY 渐变中心x、y
     - android:startColor android:centerColor android:endColor 开始中间结束的颜色
     - android:gradientRadius 渐变的半径,当android:type=”radial”有效
     - android:useLevel 一般为false
     - android:type 渐变类别,linear(线性)为默认值,radial(径内渐变),sweep(扫描渐变)

 - solid 纯色填充
     - android:color 填充色

 - stroke 描边
     - android:width 描述边框的宽度,数值越大,越边框越厚
     - android:color 边框的颜色
     - android:dashWidth 组成虚线的线段宽度
     - android:dashGap 组成虚线的线段之间的间隔,间隔越大,虚线看起的间隙就越大


 - padding 表示内容或子标签边距,4个属性top、bottom、left、right,需要注意的是这个标签的作用是为内容设置与当前应用此shape的View的边距,而不是设置当前View与父元素的边距
 - size 设置背景大小,width和height俩属性。一般来说这个值不是shape的最终显示大小,因为shape作为背景时会根据View的大小而填充其背景,因此Shape的大小很多时候是View的大小决定的
  • LayerDrawable多个drawable多层叠加
    • < layer-list >
      • < item >
  • StateListDrawable状态集,定义不同状态时drawable的不同
    • < selector >
      • < item >
  • LevelListDrawable与状态集类似,是一个等级集;ImageView可以通过setImageLevel来改变的等级
    • < level-list >
      • < item >
  • TransitionDrawable两个drawable之间的淡入淡出效果
  • InsetDrawable内嵌其他drawable并可以撑开一定的空间
  • ScaleDrawable根据等级 来缩放drawable
  • ClipDrawable根据等级来裁剪drawable
    这里写图片描述

eg:利用drawable来绘制圆角/圆形图片

public class RoundImageDrawable extends Drawable  
{  

    private Paint mPaint;  
    private Bitmap mBitmap;  

    private RectF rectF;  

    public RoundImageDrawable(Bitmap bitmap)  
    {  
        mBitmap = bitmap;  
        BitmapShader bitmapShader = new BitmapShader(bitmap, TileMode.CLAMP,  
                TileMode.CLAMP);  
        mPaint = new Paint();  
        mPaint.setAntiAlias(true);  
        mPaint.setShader(bitmapShader);  
    }  

    @Override  
    public void setBounds(int left, int top, int right, int bottom)  
    {  
        super.setBounds(left, top, right, bottom);  
        rectF = new RectF(left, top, right, bottom);  
    }  

    @Override  
    public void draw(Canvas canvas)  
    {  
        canvas.drawRoundRect(rectF, 30, 30, mPaint); //画圆角
        //也可以画圆
        //canvas.drawCircle(mWidth / 2, mWidth / 2, mWidth / 2, mPaint);   
    }  

    @Override  
    public int getIntrinsicWidth()  
    {  
        return mBitmap.getWidth();  
    }  

    @Override  
    public int getIntrinsicHeight()  
    {  
        return mBitmap.getHeight();  
    }  

    @Override  
    public void setAlpha(int alpha)  
    {  
        mPaint.setAlpha(alpha);  
    }  

    @Override  
    public void setColorFilter(ColorFilter cf)  
    {  
        mPaint.setColorFilter(cf);  
    }  

    @Override  
    public int getOpacity()  
    {  
        return PixelFormat.TRANSLUCENT;  
    }  

}  

使用

Bitmap bitmap = BitmapFactory.decodeResource(getResources(),  
                R.drawable.mv);  
        ImageView iv = (ImageView) findViewById(R.id.id_one);  
        iv.setImageDrawable(new RoundImageDrawable(bitmap));  

eg:自定义进度条
自定义旋转动画progress_rotate.xml,drawable可定义为任何自旋转可做进度条的视图

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/shape_drawable"
    android:pivotX="50%"
    android:pivotY="50%"
    android:fromDegrees="0"
    android:toDegrees="360"
    >
</rotate>

设置style

<style name="CustomProgressStyle" >
    <item name="android:indeterminateDrawable">@drawable/progress_rotate</item>
    <item name="android:minWidth">72dp</item>
    <item name="android:maxWidth">72dp</item>
    <item name="android:minHeight">72dp</item>
    <item name="android:maxHeight">72dp</item>
</style>

使用

<ProgressBar
     android:layout_width="100dp"
     android:layout_height="100dp"
     android:layout_centerInParent="true"
     style="@style/CustomProgressStyle"
     android:indeterminateDuration="700"
     />

eg:圆形角标
设置shape

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval"
    >
    <solid android:color="#D90E0E" />
    <size android:height="10dp" android:width="10dp" />
</shape>

TextView中使用

<TextView
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:layout_centerInParent="true"
    android:gravity="center"
    android:textColor="#fff"
    android:text="99"
    android:background="@drawable/shape_circle_number"
    />

eg:输入框效果
这里写图片描述
xml设置

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
      <shape android:shape="rectangle">
          <solid android:color="@color/colorAccent" />
      </shape>
    </item>

    <item android:bottom="6dp">
        <shape android:shape="rectangle">
            <solid android:color="#ffffff"/>
        </shape>
    </item>

    <item android:bottom="2dp"
          android:left="2dp"
          android:right="2dp">
        <shape android:shape="rectangle">
            <solid android:color="#ffffff" />
        </shape>
    </item>
</layer-list>

使用

<EditText                                        
  android:layout_width="200dp"                 
  android:layout_height="wrap_content"         
  android:layout_centerInParent="true"         
  android:background="@drawable/layer_drawable"
  /> 

帧动画

代码实现AnimationDrawable
xml实现

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/a_0"
        android:duration="100" />
    <item
        android:drawable="@drawable/a_1"
        android:duration="100" />
    <item
        android:drawable="@drawable/a_2"
        android:duration="100" />
</animation-list>

补间动画

平移动画TranslateAnimation、缩放动画ScaleAnimation、旋转动画RotateAnimatioin、透明度动画AlphaAnimation
自定义动画:通过矩阵变换来实现,可用来做3D动画!继承Animation,实现initialize(初始化工作)、applyTransFormation(动画实现)即可。

常见属性

  • < translate>
    ■ 表示x的起始值
    ■ 表示x的结束值
    ■ 表示y的起始值
    ■ 表示y的结束值
  • < scale>
    ■ fromX 水平方向缩放起始值
    ■ toX 水平方向缩放结束值
    ■ fromY
    ■ toY
    ■ pivotX 缩放的轴点的x坐标
    ■ pivotY 缩放的轴点的y坐标
    ■ pivotXType x轴的所发模式,即中心点相对于哪个物体Animation.ABSOLUTE/RELATIVE_TO_SELF/RELATIVE_TO_PARENT
    ■ pivotYType y轴的所发模式
  • < rotate>
    ■ fromeDegres旋转开始的角度
    ■ toDegrees
    ■ pivotX旋转的轴点的x坐标
    ■ pivotY
  • < alpha>
    ■ fromAlpha透明度起始值
    ■ toAlpha透明度结束值
  • 共有属性
    ■duration动画持续时间
    ■ fillAfter动画结束后是否停留在结束位置

布局动画LayoutAnimation,为容器型控件里的子View设置动画
代码实现LayoutAnimationController
xml实现

android:delay子类动画时间间隔 
android:animationOrder="random"   子类的显示方式 normal默认random随机reverse倒序
android:animation="@anim/slide_right" 表示孩子显示时的具体动画是什么

自定义补间动画

public class MyAnimation extends Animation
{
    @Override
    protected void applyTransformation(float interpolatedTime,Transformation transformation){
    //interpolatedTime表示动画的时间进行比,transformation表示补间动画在不同时刻对View的变形程度
    }
}

AnimationSet组合动画

属性动画

  • ObjectAnimator
ObjectAnimator//  
         .ofFloat(view, "rotationX", 0.0F, 360.0F)//  
         .setDuration(500)//  
         .start(); 

一次性修改多个属性

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f,  
                0f, 1f);  
        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f,  
                0, 1f);  
        PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f,  
                0, 1f);  
        ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY,pvhZ).setDuration(1000).start();
  • ValueAnimator
ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight  
                - mBlueBall.getHeight());  
        animator.setTarget(mBlueBall);  
        animator.setDuration(1000).start();  
//      animator.setInterpolator(value)  
        animator.addUpdateListener(new AnimatorUpdateListener()  
        {  
            @Override  
            public void onAnimationUpdate(ValueAnimator animation)  
            {  
                mBlueBall.setTranslationY((Float) animation.getAnimatedValue());  
            }  
        }); 

常见属性
这里写图片描述

AnimatorSet 用于控制一组动画的执行:线性,一起,每个动画的先后执行等。
AnimatorInflater 用户加载属性动画的xml文件

  • 过渡动画Transition
    本质上过渡动画也还是属性动画,只不过做了一层封装,方便实现Activity和View的过渡效果

绘制辅助

Interpplator 插值器

  • AccelerateDecelerateInterpolator:开始与结束时速度快,中间慢
  • AccelerateInterpolator:开始慢然后加速
  • CycleInterpolator:动画循环播放特定的次数,速率改变沿着正弦曲线
  • DecelerateInterpolator:开始速度快然后减速
  • LinearInterpolator:均匀的改变速度

TypeEvaluator 类型估值,主要用于设置动画操作属性的值。设置 属性值 从初始值过渡到结束值 的变化具体数值

  • IntEvaluator Int类型估值器,返回int类型的属性改变
  • FloatEvaluator Float类型估值器,返回Float类型属性改变
  • ArgbEvaluator 颜色类型估值器
// 实现TypeEvaluator接口
public class PointEvaluator implements TypeEvaluator {
    // 复写evaluate()在里面写入对象动画过渡的逻辑
    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        //fraction为插值器getInterpolation()的返回值,startValue/endValue为初始值/结束值
        // 将动画初始值startValue 和 动画结束值endValue 强制类型转换成Point对象
        Point startPoint = (Point) startValue;
        Point endPoint = (Point) endValue;

        // 根据fraction来计算当前动画的x和y的值
        float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
        float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());

        // 将计算后的坐标封装到一个新的Point对象中并返回
        Point point = new Point(x, y);
        return point;
    }

}

其他

overridePendingTransition Acitivity之间跳转动画

View位移的五种办法

  • layout
  • offsetTopAndBottom、offsetLeftAndRight
  • scrollTo、scrollBy
  • LayoutParams
  • Scroller

invalidate最后也是通过调用rootView的performTraversals()来刷新视图的;而invalidate只会重新执行onDraw;requestLayout才会重新执行整个绘制过程
这里写图片描述


measure、layout、draw

自定义View的四种构造函数

// 如果View是在Java代码里面new的,则调用第一个构造函数
 public CarsonView(Context context) {
        super(context);
    }

// 如果View是在.xml里声明的,则调用第二个构造函数
// 自定义属性是从AttributeSet参数传进来的
    public  CarsonView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

// 不会自动调用
// 一般是在第二个构造函数里主动调用
// 如View有style属性时
    public  CarsonView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    //API21之后才使用
    // 不会自动调用
    // 一般是在第二个构造函数里主动调用
    // 如View有style属性时
    public  CarsonView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

View的一些常见函数

view.getTop() 子View左上角距父View顶部的距离
view.getBottom() 子View右下角距父View顶部的距离
view.getLeft() 子View左上角距父View左侧
view.getRight() 子View右下角距父View左侧
event.getX()/event.getY() 触摸点相对于其所在组件坐标系的坐标
event.getRawX()/event.getRawY() 触摸点相对于屏幕默认坐标系的坐标

颜色

这里写图片描述

Measure

LayoutParams(View 自身的布局参数)
这里写图片描述
MeasureSpecs 类(父视图对子视图的测量要求)
MeasureSpecs维护一个int型(32bit)数据,其中2bit表示mode,30bit表示size

size = MeasureSpec.getSize(measureSpec)
mode = MeasureSpec.getMode(measureSpec)
measureSpec = MeasureSpec.makeMeasureSpec(size, mode)
getDefaultSize(size,measureSpec)//根据View默认大小size和父类measureSpec来测量当前View的大小

mode
这里写图片描述

一个View的大小由父容器的MeasureSpecs和自身的LayoutParams来决定
这里写图片描述
setMeasureDimension()属于View类,保存最终的测试大小

View的测量过程
这里写图片描述

eg:修改ListView的onMeasure使得ListView完全展开

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    //int widthMeasureSpec, int heightMeasureSpec是父容器的测量spec,现将父容器的高度测量spec修改成足够大,并且是AT_MOST模式,这样子容器即ListView认为父容器有足够大的空间就会将所有的内容完全展开了。
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

layout

view的layout过程:layout(确定自身的位置)->onLayout(空实现)
ViewGroup的layout过程:layout(确定自身的位置)->onLayout(确定子控件的位置,这里实现具体布局,并且会遍历子控件的layout对子控件执行layout)

draw

这里写图片描述

注意点

  • 支持padding & margin
    padding需要在onDraw中获取在绘制过程中进行支持
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int paddingTop = getPaddingTop();
final int paddingBottom = getPaddingBottom();
  • 支持自定义属性
    在values目录下创建自定义属性的xml文件attrs_circle_view.xml
    常用单位format:color boolean dimension float integer string fraction(百分比) enum(eg:orientation,单选) flag(eg:adjustResize|adjustPan,多选)
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CircleView">
        <attr name="circle_color" format="color"/>
    </declare-styleable>
</resources>

在代码中解析获取

mColor = a.getColor(R.styleable.CircleView_circle_color,Color.RED);

在布局中使用

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >
    <scut.carson_ho.diy_view.CircleView
        app:circle_color="#FF4081"
         />
</RelativeLayout>
  • 支持wrap_content
    修改onMeasure
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // 获取宽-测量规则的模式和大小
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        // 获取高-测量规则的模式和大小
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        // 设置wrap_content的默认宽 / 高值
        // 默认宽/高的设定并无固定依据,根据需要灵活设置
        // 类似TextView,ImageView等针对wrap_content均在onMeasure()对设置默认宽 / 高值有特殊处理,具体读者可以自行查看
        int mWidth = 400;
        int mHeight = 400;

      // 当布局参数设置为wrap_content时,设置默认值
        if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT && getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
            setMeasuredDimension(mWidth, mHeight);
        // 宽 / 高任意一个布局参数为= wrap_content时,都设置默认值
        } else if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) {
            setMeasuredDimension(mWidth, heightSize);
        } else if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
            setMeasuredDimension(widthSize, mHeight);
        }
  • post替代handler,View的内部本身提供了post系列的方法,完全可以替代Handler的作用,使用起来更加方便、直接。
  • onAttachedToWindow,调用的时机是当包含View的Activity启动的时刻,适合启动线程/动画/注册各种东东
  • onDetachedFromWindow,调用的时机是当包含View的Activity退出或当前View被remove的时刻,适合结束线程/动画/注销各种东东

视图的状态

  • focused
    表示当前视图是否获得到焦点。通常情况下有两种方法可以让视图获得焦点,即通过键盘的上下左右键切换视图,以及调用requestFocus()方法。而现在的Android手机几乎都没有键盘了,因此基本上只可以使用requestFocus()这个办法来让视图获得焦点了。而requestFocus()方法也不能保证一定可以让视图获得焦点,它会有一个布尔值的返回值,如果返回true说明获得焦点成功,返回false说明获得焦点失败。一般只有视图在focusable和focusable in touch mode同时成立的情况下才能成功获取焦点,比如说EditText

  • window_focused
    表示当前视图是否处于正在交互的窗口中,这个值由系统自动决定,应用程序不能进行改变。

  • selected
    表示当前视图是否处于选中状态。一个界面当中可以有多个视图处于选中状态,调用setSelected()方法能够改变视图的选中状态,传入true表示选中,传入false表示未选中。

  • pressed
    表示当前视图是否处于按下状态。可以调用setPressed()方法来对这一状态进行改变,传入true表示按下,传入false表示未按下。通常情况下这个状态都是由系统自动赋值的,但开发者也可以自己调用这个方法来进行改变。
    我们可以在项目的drawable目录下创建一个selector文件,在这里配置每种状态下视图对应的背景图片

  • enabled
    表示当前视图是否可用。可以调用setEnable()方法来改变视图的可用状态,传入true表示可用,传入false表示不可用。它们之间最大的区别在于,不可用的视图是无法响应onTouch事件的


Canvas

常用方法
这里写图片描述

注:
//addArc(Rect,startAngle,sweepAngle)startAngle:确定角度的起始位置 sweepAngle : 确定扫过的角度
//扫过的角度360为顺时针一圈,-360为逆时针一圈,但如果扫过的角度超过360则起点会变成0度而非startAngle百分比圆的时候特别注意,这时候一般设置为359

Paint

常见属性

//设置画笔的粗细
mPaint.setStrokeWidth(float width)       
// 如设置画笔宽度为10px
mPaint.setStrokeWidth(10f);        
// 设置Shader 即着色器,定义了图形的着色、外观 可以绘制出多彩的图形
Paint.setShader(Shader shader)  
//设置画笔的a,r,p,g值
mPaint.setARGB(int a, int r, int g, int b)      
//设置透明度
mPaint.setAlpha(int a)         
//设置字体大小
mPaint.setTextSize(float textSize)       
// 文字Style三种模式:
// 类型1:Paint.Style.FILLANDSTROKE(描边+填充)
// 类型2:Paint.Style.FILL(只填充不描边)
// 类型3:Paint.Style.STROKE(只描边不填充)
mPaint.setStyle(Style style); 
// 设置对齐方式 LEFT:左对齐 CENTER:居中对齐 RIGHT:右对齐
setTextAlign()
//设置文本的下划线
setUnderlineText(boolean underlineText)      
//设置文本的删除线
setStrikeThruText(boolean strikeThruText)    
//设置文本粗体
setFakeBoldText(boolean fakeBoldText)  
// 设置斜体
Paint.setTextSkewX(-0.5f);
// 设置文字阴影
Paint.setShadowLayer(5,5,5,Color.YELLOW);

path

  • 基础路径设置:moveTo/setLastPoint设置当前位置即起始点(前者不受之前的操作影响,后者会)、lineTo连接到此点、close闭合路径
  • 重置路径 reset、rewind(前者保留FillType不保留原始数据;后者不保留FillType保留原始数据)
  • 常用方法
//圆弧路径 startAngle:确定角度的起始位置 sweepAngle : 确定扫过的角度
//扫过的角度360为顺时针一圈,-360为逆时针一圈,但如果扫过的角度超过360则起点会变成0度而非startAngle百分比圆的时候特别注意,这时候一般设置为359
addArc (RectF oval, float startAngle, float sweepAngle)
//与上面方法唯一不同的是:如果圆弧的起点和上次最后一个坐标点不相同,就连接两个点
arcTo (RectF oval, float startAngle, float sweepAngle)
//圆弧路径 forceMoveTo:是否将之前路径的结束点设置为圆弧起点
arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)
//圆形路径 dir:指定绘制时是顺时针还是逆时针:CW为顺时针,CCW为逆时针路径起点变为圆在X轴正方向最大的点
addCircle(float x, float y, float radius, Path.Direction dir) 
// 椭圆形路径 oval作为椭圆的外切矩形区域
addOval(RectF oval, Path.Direction dir)  
//矩形路径
addRect(RectF rect, Path.Direction dir)  
//圆角矩形路径
addRoundRect(RectF rect, float rx, float ry, Path.Direction dir) 
  • addPath合并路径
  • isEmpty()、 isRect()、isConvex()、 set() 和 offset()
  • 设置填充规则path.setFillType()
// 1. EVEN_ODD:奇偶规则
// 2. INVERSE_EVEN_ODD:反奇偶规则
// 3. WINDING :非零环绕数规则
// 4. INVERSE_WINDING:反非零环绕数规则
  • 路径间运算
    newPath.op(path1, path2, Path.Op.DIFFERENCE)
    这里写图片描述

  • PathMeasure

Layer

贝塞尔曲线

数据点:指路径的起始点和终止点;
控制点:决定了路径的弯曲轨迹;
n+1阶贝塞尔曲线 = 有n个控制点;
(1阶 = 一条直线,高阶可以拆解为多条低阶曲线)

// 绘制二阶贝塞尔曲线
//  (x1,y1)为控制点,(x2,y2)为终点
quadTo(float x1, float y1, float x2, float y2)
//  (x1,y1)为控制点距离起点的偏移量,(x2,y2)为终点距离起点的偏移量
rQuadTo(float x1, float y1, float x2, float y2)

// 绘制三阶贝塞尔曲线
// (x1,y1),(x2,y2)为控制点,(x3,y3)为终点
cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
// (x1,y1),(x2,y2)为控制点距离起点的偏移量,(x3,y3)为终点距离起点的偏移量
rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3)

贝塞尔曲线开发的艺术
贝赛尔曲线模拟器

Tencent OS录音机波形动http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=1180
函数模拟https://www.desmos.com/calculator
那些年我们用过的显示性能指标http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=936

其他

  • 硬件加速 android:hardwareAccelerated=”false”

Canvas类的最全面详解

trasation?
scroller?
recyclerview.itemTouchHelper?

猜你喜欢

转载自blog.csdn.net/xiaoru5127/article/details/78081116