Android 自定义View 开发 入门与实践1 与 安卓属性动画

安卓动画:  参照博客:http://blog.csdn.net/lmj623565791/article/details/38067475
逐帧动画  补间动画  属性动画
逐帧动画:Drawable Animation  ,FrameAnimation  对一个ImageView 不停的设置新的图片
补间动画:ViewAnimation ,也叫Tweened Animation  平移,缩放,透明,旋转  有局限性.
属性动画:PropertyAnimation  补间动画的升级 :通过动画的方式改变对象的属性

属性动画与补间动画最大的区别就是,控件通过属性动画改变位置后,控件的位置会随着改变,而补间动画控件还是在原地

相关类:(类似于ImageLoader的框架)
 动画的执行类 :ObjectAnimator,ValueAnimator
 AnimatorSet:动画集合
 AnimatorInflater:加载文件夹为animator的XML文件
 TypeEvaluator:类型估值,只要用于设置动画操作属性的值
 TimeInterpolator:时间插值器(也叫插补器). 设置动画加速减速.变化率
    属性动画执行流程:动画的执行类来设置动画操作的对象的属性.持续时间,开始和结束的属性值,时间插值等,然后系统会根据设置的参数,动态的变化对象的属性.
    
    PropertyName 有四个
    translationXY,rotation,alpha,scaleXY
    translationXY和scaleXY只有后缀加XY的方法,不表明XY方向的画会出现找不到方法的错误.    注意XY必须大写.我们将他们作为字符串当做参数传入方法里,由刚才的错误可以发现这个字符串是作为一个方法名来运行的.
    通过方法
    ObjectAnimator.ofFloat.setDuration.start
    简单实现
    也可以通过
    PropertyValuesHolder 属性持有者这个属性来设置同时播放俩种动画
    方法
     ObjectAnimator.ofPropertyValuesHolder.setDuration.start这个方法参数是一个可变数组
    示例代码:
    case R.id.image:
                //TODO
                ObjectAnimator//3个参数:作用对象  动画名  动画需要配置的值:可变数组
                        .ofFloat(mImage, "translationX", 30f,90f)
//                        .ofFloat(mImage, "translationX", 90f,30f)
                        .setDuration(1500)
                        .start();
                        
    之前的补间动画有AnimationSet实现多种动画组合播放,而属性动画也有这个功能就是AnimatorSet
    
    AnimatorSet通过Play().with().after().before()通过这些方法来实现 动画和动画的先后顺序,以及同时播放功能.
    
    修改背景色:闪光灯效果  方法名:backgroundColor字符串
    ObjectAnimator.ofInt  至于颜色则是通过可变参数实现
    关于属性动画插值器的笔记
    Interpolator,在安卓1.0的时候就已经出现Interpolator接口了,可以翻译成插值器,用于计算补间动画的变化速率. 而在安卓3.0的时候引入了属性动画,同时新增了TimeInterpolator接口,这就使得
    Interpolator的实现类可以直接拿到属性动画中使用.
    主要的实现类
    AccelerateDecelerateInterpolator   在动画开始与介绍的地方速率改变比较慢,在中间的时候加速
    AccelerateInterpolator                     在动画开始的地方速率改变比较慢,然后开始加速
    AnticipateInterpolator                      开始的时候向后然后向前甩
    AnticipateOvershootInterpolator     开始的时候向后然后向前甩一定值后返回最后的值
    BounceInterpolator                          动画结束的时候弹起
    CycleInterpolator                             动画循环播放特定的次数,速率改变沿着正弦曲线
    DecelerateInterpolator                    在动画开始的地方快然后慢
    LinearInterpolator                            以常量速率改变
    OvershootInterpolator                      向前甩一定值后再回到原来位置
    
    使用:一个方法  animator.setInterpolator(new BounceInterpolator());
    实例代码:
      ObjectAnimator animator = ObjectAnimator
                        .ofFloat(mImage, "rotationY", 0.0f, 360f);
                animator.setInterpolator(new BounceInterpolator());
                animator.setDuration(5000)
                        .start();
    属性动画课堂笔记
    ObjectAnimator属性动画特点:动画效果会改变控件的位置,且开启动画的是动画对象,而不是控件对象.
    注意:
       如果你想让你的App与众不同,请用自定义控件,
       吊炸天+狂拽=android动画+自定义动画
    
    Android3.0之后才出现的新特性.最低兼容API11
    
    在XML定义动画类属性,浮点型小数,直接写小数即可,不用再带f
    提示:控件位移的参数在XML文件里有所不同,不过更简单,不用再特意去定义参照物的属性,直接根据值,区分俩种方式.
    一种:一整个屏幕为参照物,在XML文件属性定义值是int%p
    一种:以控件自身大小为参照物,
    使用方式:
    示例代码
     Animator animator1 = AnimatorInflater.loadAnimator(MainActivity.this, R.animator.set);
                animator1.setTarget(mImage);
                animator1.start();
    ValueAnimator 实现动画
    无需设置操作的属性,这就是和ObjectAnimator的区别
    好处:不需要操作对象的属性,一定要有getter,setter方法,你可以根据当前动画的计算值,来操作任何属性
    
    示例代码
    private void Vertical() {//heightPixels - mImage.getHeight()
        final ValueAnimator animator = ValueAnimator.ofFloat(0,300 );
        animator.setTarget(mImage);
        animator.setDuration(2000).start();
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mImage.setTranslationY((float)animator.getAnimatedValue());
            }
        });
    }

 

 

 

 

/*********************************/

 

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    int duration = 500;
    private ImageView mImageJia;
    private ImageView mImageIc1;
    private ImageView mImageIc2;
    private RelativeLayout mRela;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();


    }

    private void initView() {

        mImageIc1 = (ImageView) findViewById(R.id.imageIc1);
        mImageIc2 = (ImageView) findViewById(R.id.imageIc2);
        mImageJia = (ImageView) findViewById(R.id.imageJia);
        mImageJia.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {

            case R.id.imageJia:
                Toast.makeText(MainActivity.this, "222", Toast.LENGTH_SHORT).show();

                StartAnimation();
                break;
        }
    }

    private boolean isChecked = false;

    private void StartAnimation() {

        if (isChecked == false) {
//        PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("TranslationX", 0f, 150f);
            ObjectAnimator animator1 = ObjectAnimator.ofFloat(mImageIc1, "TranslationX", 0f, 150f);
            ObjectAnimator animator2 = ObjectAnimator.ofFloat(mImageIc2, "TranslationX", 0f, 300f);
            ObjectAnimator animator3 = ObjectAnimator.ofFloat(mImageJia, "Rotation", 0f, 360f);
            //添加自由落体效果插值器
            animator1.setInterpolator(new BounceInterpolator());
            animator2.setInterpolator(new BounceInterpolator());
            animator3.setInterpolator(new BounceInterpolator());

            //启动动画
            animator1.setDuration(duration).start();
            animator2.setDuration(duration).start();
            animator3.setDuration(duration).start();

            animator3.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {

                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    mImageJia.setImageResource(R.drawable.jian);
                }

                @Override
                public void onAnimationCancel(Animator animation) {

                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }
            });

            isChecked = true;
        } else {
            ObjectAnimator animator1 = ObjectAnimator.ofFloat(mImageIc1, "TranslationX",  150f,0f);
            ObjectAnimator animator2 = ObjectAnimator.ofFloat(mImageIc2, "TranslationX", 300f,0f );
            ObjectAnimator animator3 = ObjectAnimator.ofFloat(mImageJia, "Rotation", 0f, 720f);
            //添加自由落体效果插值器
//            animator1.setInterpolator(new CycleInterpolator(1));
//            animator2.setInterpolator(new CycleInterpolator(5));
//            animator3.setInterpolator(new CycleInterpolator(10));

            //启动动画
            animator1.setDuration(duration).start();
            animator2.setDuration(duration).start();
            animator3.setDuration(duration).start();
            animator3.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {

                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    mImageJia.setImageResource(R.drawable.jia);
                }

                @Override
                public void onAnimationCancel(Animator animation) {

                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }
            });

            isChecked = false;
        }

    }
}

补充:


public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private ImageView mImage;
    private Button mButAlpha;
    private Button mButScale;
    private Button mButTranslatatin;
    private Button mBuRotation;
    private Button mButSR;
    private Button mButRT;
    private Button mButAlphaRepeat;
    private Button mBuBGcolor;
    private Button mButPaoWuxian;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        mImage = (ImageView) findViewById(R.id.image);
        mButAlpha = (Button) findViewById(R.id.butAlpha);
        mButAlpha.setOnClickListener(this);
        mButScale = (Button) findViewById(R.id.butScale);
        mButScale.setOnClickListener(this);
        mButTranslatatin = (Button) findViewById(R.id.butTranslatatin);
        mButTranslatatin.setOnClickListener(this);
        mBuRotation = (Button) findViewById(R.id.buRotation);
        mBuRotation.setOnClickListener(this);
        mButSR = (Button) findViewById(R.id.butSR);
        mButSR.setOnClickListener(this);
        mButRT = (Button) findViewById(R.id.butRT);
        mButRT.setOnClickListener(this);
        mButAlphaRepeat = (Button) findViewById(R.id.butAlphaRepeat);
        mButAlphaRepeat.setOnClickListener(this);
        mBuBGcolor = (Button) findViewById(R.id.buBGcolor);
        mBuBGcolor.setOnClickListener(this);
        mButPaoWuxian = (Button) findViewById(R.id.butPaoWuxian);
        mButPaoWuxian.setOnClickListener(this);
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.butAlpha://透明
                ObjectAnimator
                        .ofFloat(mImage, "alpha", 0.0f, 1.0f)
                        .setDuration(1000)
                        .start();

                break;
            case R.id.butScale://缩放   同时播放俩种 XY并存的都可以这样写
                ObjectAnimator
                        .ofFloat(mImage, "scaleX", 0.0f, 1.0f)
                        .setDuration(1000)
                        .start();
                break;
            case R.id.butTranslatatin://位移
                PropertyValuesHolder translationX = PropertyValuesHolder.ofFloat("translationX", 20f, 80f);
                PropertyValuesHolder translationY = PropertyValuesHolder.ofFloat("translationY", 20f, 80f);
                ObjectAnimator
                        .ofPropertyValuesHolder(mImage, translationX, translationY)
                        .setDuration(1000)
                        .start();
                break;
            case R.id.buRotation://旋转
                ObjectAnimator
                        .ofFloat(mImage,"rotationY",0.0f,360f)
                        .setDuration(1000)
                        .start();
                break;
            case R.id.butSR://先播放缩放动画,完成后播放旋转动画
                AnimatorSet animatorSetGroup1 = new AnimatorSet();
                ObjectAnimator objectAnimatorScaleX1 = ObjectAnimator.ofFloat(mImage, "scaleX", 0f, 1f);
                ObjectAnimator objectAnimatorScaleY1 = ObjectAnimator.ofFloat(mImage, "scaleY", 0f, 1f);
                ObjectAnimator objectAnimatorRotateX1 = ObjectAnimator.ofFloat(mImage, "rotationX", 0f, 360f);
                ObjectAnimator objectAnimatorRotateY1 = ObjectAnimator.ofFloat(mImage, "rotationY", 0f, 360f);
                animatorSetGroup1.setDuration(1000);
                animatorSetGroup1.play(objectAnimatorScaleX1).with(objectAnimatorScaleY1)
                        .before(objectAnimatorRotateX1).before(objectAnimatorRotateY1);
                animatorSetGroup1.start();
                break;
            case R.id.butRT://先播放旋转动画,完成后播放位移动画
                AnimatorSet animatorSetGroup2 = new AnimatorSet();
                ObjectAnimator objectAnimatorTranslate2 = ObjectAnimator.ofFloat(mImage, "translationX", 0f, 500f);
                ObjectAnimator objectAnimatorRotateX2 = ObjectAnimator.ofFloat(mImage, "rotationX", 0f, 360f);
                ObjectAnimator objectAnimatorRotateY2 = ObjectAnimator.ofFloat(mImage, "rotationY", 0f, 360f);
                animatorSetGroup2.setDuration(1000);
                animatorSetGroup2.play(objectAnimatorTranslate2).after(objectAnimatorRotateX2)
                        .after(objectAnimatorRotateY2);
                animatorSetGroup2.start();
                break;
            case R.id.butAlphaRepeat://重复的透明度动画  闪烁效果
                //TODO
                ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mImage, "alpha", 0f, 1f);
                objectAnimator2.setDuration(500);
                objectAnimator2.setRepeatCount(3);
                objectAnimator2.start();
                break;
            case R.id.buBGcolor://背景颜色不断改变
                //TODO
                ObjectAnimator objectAnimatorBg = ObjectAnimator.ofInt(mImage, "backgroundColor", Color.BLUE, Color.YELLOW, Color.RED);
                objectAnimatorBg.setDuration(3000);
                objectAnimatorBg.start();
                break;
            case R.id.butPaoWuxian://背景颜色不断改变
                //TODO
                parabola();
                break;
            default:
                break;
        }
    }
    /**
     * 抛物线动画
     */
    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
    public void parabola()
    {

        ValueAnimator valueAnimator = new ValueAnimator();
        valueAnimator.setDuration(3000);
        valueAnimator.setObjectValues(new PointF(0, 0));
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.setEvaluator(new TypeEvaluator<PointF>()
        {

            @Override
            public PointF evaluate(float fraction, PointF startValue,
                                   PointF endValue)
            {
                /**x方向200px/s ,则y方向0.5 * 200 * t**/
                PointF point = new PointF();
                point.x = 200 * fraction * 3;
                point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);
                return point;
            }
        });

        valueAnimator.start();
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
        {
            @Override
            public void onAnimationUpdate(ValueAnimator animation)
            {
                PointF point = (PointF) animation.getAnimatedValue();
                mImage.setX(point.x);
                mImage.setY(point.y);

            }
        });
    }
}

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical">


        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <Button
                android:id="@+id/butAlpha"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="透明" />

            <Button
                android:id="@+id/butScale"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="缩放" />

            <Button
                android:id="@+id/butTranslatatin"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="位移" />

            <Button
                android:id="@+id/buRotation"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="旋转" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <Button
                android:id="@+id/butSR"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="先缩放后旋转"
                android:textSize="14sp" />

            <Button
                android:id="@+id/butRT"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="先旋转后位移"
                android:textSize="14sp" />

            <Button
                android:id="@+id/butAlphaRepeat"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="透明重放:闪烁"
                android:textSize="14sp" />

            <Button
                android:id="@+id/buBGcolor"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="背景色改变"
                android:textSize="14sp" />
        </LinearLayout>

        <Button
            android:id="@+id/butPaoWuxian"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="抛物线动画"
            android:textSize="14sp" />

        <ImageView
            android:id="@+id/image"
            android:layout_width="200dp"
            android:layout_height="250dp"
            android:layout_gravity="center"
            android:layout_marginTop="200dp"
            android:src="@drawable/cat" />


    </LinearLayout>

</layout>

 

 

 

 


 

时隔俩年,现在加一些

<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">


        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="weiyi"
            android:text="开始位移" />

        <Button
            android:id="@+id/biaozhi"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="标志" />


    </LinearLayout>

        mViewBinding.biaozhi.layout(mViewBinding.biaozhi.getWidth(), mViewBinding.biaozhi.getHeight(), mViewBinding.biaozhi.getWidth()*2, mViewBinding.biaozhi.getHeight()*2);

 

 

 

layout是改变view在布局的大小和位置

让他向右移,只需要改变右和下方向的距离,我们可以 根据结束的位置来写最终位置的俩个点(左,上),(右,下)

 

 

 

ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 400);

        int width = mViewBinding.biaozhi.getWidth();
        int height = mViewBinding.biaozhi.getHeight();

        valueAnimator.setDuration(3000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int curValue = (int) animation.getAnimatedValue();
                mViewBinding.biaozhi.layout(curValue, height + curValue, width + curValue, height * 2 + curValue);
            }
        });
        valueAnimator.start();

做一个loading

public class MyView extends ImageView {


    /**
     * 距上
     */
    private int mTop;


    /**
     * 当前图片索引 也就是第几张开始
     */
    private int mCurSrc = 0;

    /**
     * 图片总数
     */
    private int mSrccount = 3;

    public MyView(Context context) {
        this(context, null);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 100, 0);

        valueAnimator.setRepeatMode(ValueAnimator.RESTART);
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator.setDuration(2000);
        valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());


        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int animatedValue = (int) animation.getAnimatedValue();

                setTop(mTop - animatedValue);
            }
        });

        valueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {

            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                switch (mCurSrc % mSrccount) {
                    case 0:
                        setImageDrawable(getResources().getDrawable(R.drawable.cat));
                        break;
                    case 1:
                        setImageDrawable(getResources().getDrawable(R.drawable.dog));
                        break;
                    case 2:
                        setImageDrawable(getResources().getDrawable(R.drawable.pig));
                        break;
                    default:
                        break;
                }

                mCurSrc++;
            }
        });

        valueAnimator.start();
    }


    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        mTop = top;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);


    }


}
  <com.as.zqfjavasample.formal.customviews.MyView
            android:layout_width="@dimen/dp50"
            android:layout_height="@dimen/dp50"
            android:layout_marginTop="@dimen/dp50"
            android:scaleType="fitXY" />

Region

public class MyView extends View {


    private Paint mPaint;

    public MyView(Context context) {
        this(context, null);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        mPaint = new Paint();

        mPaint.setAntiAlias(true);//设置抗锯齿
        mPaint.setColor(Color.BLACK);//设置画笔颜色
        mPaint.setDither(true);// 防止抖动
        mPaint.setStyle(Paint.Style.STROKE); // 边框
        mPaint.setStrokeWidth(10);//宽度

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        Rect mRect = new Rect(100, 100, 500, 300);
        Region mRegion = new Region(mRect);
        drawRegion(canvas, mRegion, mPaint);

    }


    private void drawRegion(Canvas canvas, Region mRegion, Paint mPaint) {
        RegionIterator iterator = new RegionIterator(mRegion);
        Rect rectF = new Rect();
        while (iterator.next(rectF)) {
            canvas.drawRect(rectF, mPaint);
        }
    }

}

类似普通的矩形,但是既然要通过Region来包装,那么这里一定是有不同寻常的Api

它可以用来画俩个区域重叠的地方

public class MyView extends View {


    private Paint mPaint;

    public MyView(Context context) {
        this(context, null);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        mPaint = new Paint();

        mPaint.setAntiAlias(true);//设置抗锯齿
        mPaint.setColor(Color.BLACK);//设置画笔颜色
        mPaint.setDither(true);// 防止抖动
        mPaint.setStyle(Paint.Style.FILL); // 边框
        mPaint.setStrokeWidth(10);//宽度

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);


        Path mPath = new Path();
        mPath.addOval(new RectF(100, 100, 500, 500), Path.Direction.CW);

        Region mRegion = new Region();

        Rect mRect = new Rect(100, 100, 500, 200);
        mRegion.setPath(mPath, new Region(mRect));

        drawRegion(canvas, mRegion, mPaint);


    }


    private void drawRegion(Canvas canvas, Region mRegion, Paint mPaint) {
        RegionIterator iterator = new RegionIterator(mRegion);
        Rect rectF = new Rect();
        while (iterator.next(rectF)) {
            canvas.drawRect(rectF, mPaint);
        }
    }

}

union函数

区域相交  合并矩形

Region region = new Region(10, 10, 510, 410);
        region.union(new Rect(10,10,310,610));
        drawRegion(canvas, region, mPaint);

op方法

 

public class MyView extends View {

    private Paint mPaint;

    public MyView(Context context) {
        this(context, null);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        mPaint = new Paint();

        mPaint.setAntiAlias(true);//设置抗锯齿
        mPaint.setColor(Color.BLACK);//设置画笔颜色
        mPaint.setDither(true);// 防止抖动
        mPaint.setStyle(Paint.Style.STROKE); // 边框
        mPaint.setStrokeWidth(10);//宽度

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);


        Rect rect1 = new Rect(100, 100, 400, 200);
        Rect rect2 = new Rect(200, 0, 300, 300);

        Region region1 = new Region(rect1);
        Region region2 = new Region(rect2);

        Region region = new Region();
//        region.op(region1, region2, Region.Op.DIFFERENCE);
//        region.op(region1, region2, Region.Op.INTERSECT);
//        region.op(region1, region2, Region.Op.REPLACE);
//        region.op(region1, region2, Region.Op.UNION);
//        region.op(region1, region2, Region.Op.XOR);
        region.op(region1, region2, Region.Op.REVERSE_DIFFERENCE);

        canvas.drawRect(rect1, mPaint);
        canvas.drawRect(rect2, mPaint);

        mPaint.setStyle(Paint.Style.FILL);
        drawRegion(canvas, region, mPaint);

    }


    private void drawRegion(Canvas canvas, Region mRegion, Paint mPaint) {
        RegionIterator iterator = new RegionIterator(mRegion);
        Rect rectF = new Rect();
        while (iterator.next(rectF)) {
            canvas.drawRect(rectF, mPaint);
        }
    }

}

canvas.save/restore

当我们对canvas(画布)进行操作后就需要对画布状态进行保存(save),恢复(restore)

举个栗子

        canvas.drawCircle(100, 100, 50, mPaint);
        canvas.translate(200, 200);
        canvas.drawCircle(100, 100, 50, mPaint);

默认的中心点是:0,0 所有100,100的圆在左上角,当我们使用translate之后画布换了位置,中心点到了200,200,所以100,100画在了右下角

 

        canvas.drawCircle(100, 100, 50, mPaint);
        canvas.save();
        canvas.translate(200, 200);
        canvas.restore();
        mPaint.setColor(Color.RED);
        canvas.drawCircle(110, 110, 50, mPaint);

可以看到这样画布恢复了,中心点又回去了

小栗子:

 

 canvas.drawCircle(500, 500, 400, mPaint);

        mPaint.setStyle(Paint.Style.FILL); // 实心


        for (int i = 0; i < 7; i++) {
            canvas.save();
            canvas.rotate(60 * i, 500, 500);
            canvas.drawLine(500, 500, 500, 0, mPaint);
            canvas.restore();
        }


        // 看看最终的中心点在哪
        canvas.drawPoint(10, 10, mPaint);

 

这个有个问题,每次打开App 然后退到后台不杀死再打开就会变成Fill 类型的

这个问题找到了原因了就是每次界面可见时,就会调用自定义View 的OnDraw ,所以

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值