自定义View,ViewGroup,SurfaceView

来源:互联网 发布:北京业之峰装饰 知乎 编辑:程序博客网 时间:2024/04/28 14:18

1.自定义ViewGroup,自定义View,在XML中写全称,即包名+类名
2.新建类继承View,有三个构造器View(Context),View(Context,AttributeSet)View(Context,AttributeSet,Style)其中,AttributeSet即View的属性,例如长宽等,Style即View的样式。
3.通常复写onMeasure和onDraw方法,onMeasure测量宽高,onDraw绘制
4.Paint画笔,方法.setColor,setTextSize,setTextAlign可设置字体居中,setAntiAlias(true)设置抗锯齿,setstyle可设置空心,.setStrokeWidth设置线条宽度等
5.canvas画布
(当需要旋转绘制时 canvas.save()保存当前画布 canvas.rotate(度数,x,y)中心点 canvas.restore()转回原来的状态

6.Path默认坐标(0,0)

//使用路径path画一个三角形        mPath.moveTo(wide / 2 - 100, 200);        mPath.lineTo(wide / 2 + 100, 200);        mPath.lineTo(wide / 2, 0);        mPath.close();//使路径闭合        canvas.drawPath(mPath, mPaint);        canvas.drawTextOnPath("这是一个三角形", mPath, 0, 0, mPaint_text);//沿曲线写文字

7.贝塞尔曲线

mPath.moveTo(100, 300);//起点        mPath.quadTo(100,500,400,400);//控制点、终点        canvas.drawPath(mPath,mPaint);

实现动态波浪

//draw方法中实现 mPath.reset();        mPath.moveTo(count, 100);        for (int i = 0; i < 10; i++) {            mPath.rQuadTo(40, 20, 80, 0);//注意count一定是一个周期的整数倍            mPath.rQuadTo(40, -20, 80, 0);//以当前点为(0,0)点        }        canvas.drawPath(mPath, mPaint);handler.sendEmptyMessageDelayed(FRESH,1000);//在构造函数中实现 private Handler handler=new Handler(){        @Override        public void handleMessage(Message msg) {            switch (msg.what){                case FRESH:                    count+=10;                    if(count>160){                        count=0;                    }                    invalidate();                    handler.sendEmptyMessageDelayed(FRESH,50);                    break;                default:                    break;            }        }    };

8.实现擦除显示图片效果或给图片加马赛克
定义一个Bitmap,在Bitmap上定义一个画布,首先在Draw方法中的画布上添加一个背景,用Bitmap的画笔先画一层纯色,再加onTouchEvent,点击处画圆或其他图形,使用porterDuffXfermode设置两层叠加时透明即可透出背景。
具体实现:
OnTouchEvent:实现在图片上滑动擦除

public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()){            case MotionEvent.ACTION_DOWN:                x=event.getX();                y=event.getY();                mPath.moveTo(x,y);                invalidate();                old_x=x;                old_y=y;                return true;            case MotionEvent.ACTION_MOVE:                x=event.getX();                y=event.getY();                mPath.moveTo(old_x, old_y);                mPath.quadTo((x + old_x) / 2, (y + old_y) / 2, x, y);                invalidate();                old_x=x;                old_y=y;                return true;        }        return super.onTouchEvent(event);

Paint:

PorterDuffXfermode mode=new PorterDuffXfermode(PorterDuff.Mode.XOR);        mPaint_square.setXfermode(mode);//必须画在Bitmap上        mPaint_square.setStrokeJoin(Paint.Join.ROUND);//设置结合处的样式。Miter:锐角, Round:圆弧:BEVEL:直线。        mPaint_square.setStrokeCap(Paint.Cap.ROUND);//画笔笔刷类型 如影响画笔但始末端        mPaint_square.setDither(true); //防抖动        mPaint_square.setStrokeWidth(paintwidth);        mPaint_square.setStyle(Paint.Style.FILL_AND_STROKE);        mPaint_square.setPathEffect(new CornerPathEffect(360));//用来控制绘制轮廓(线条)的方式, 可以使用圆角来代替尖锐的角从而对基本图形的形状尖锐的边角进行平滑。

将一个View当前的截图进行保存

mButton_save_picture.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                myBitmapTwo.setDrawingCacheEnabled(true);                Bitmap bitmap=myBitmapTwo.getDrawingCache(true);                File file=new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".jpg");                try {                    file.createNewFile();                } catch (IOException e) {                    e.printStackTrace();                }                try {                    bitmap.compress(Bitmap.CompressFormat.JPEG,100,new FileOutputStream(file));                    //100 是压缩率,如果写30,表示压缩70%; 如果不压缩是100,表示压缩率为0                } catch (FileNotFoundException e) {                    e.printStackTrace();                }                Toast.makeText(PictureActivity.this, "保存成功", Toast.LENGTH_SHORT).show();            }        });

9.自定义属性
A.values文件夹下新建xml

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="myview">//名字与xmlns中声明的要一致        <attr name="myview_background" format="reference"></attr>        <attr name="myview_paintwidth" format="dimension|reference"></attr>    </declare-styleable></resources>

B.xml中

//声明xmlns:myview="http://schemas.android.com/apk/res-auto"//View中的属性截取android:layout_height="match_parent"        myview:myview_background="@mipmap/aa"        myview:myview_paintwidth="50dp"/>

C.自定义View中

public MyBitmapTwo(Context context, AttributeSet attrs) {        super(context, attrs);        final TypedArray a=context.obtainStyledAttributes(attrs,R.styleable.myview);//attrs是xml中声明此view的属性集合,将列表与后面定义的属性去比对        BitmapDrawable drawable= (BitmapDrawable) a.getDrawable(R.styleable.myview_myview_background);        int paintwidth=a.getDimensionPixelOffset(R.styleable.myview_myview_paintwidth,30);        if(drawable!=null){            mBitmapBackground= drawable.getBitmap();        }else{            mBitmapBackground= BitmapFactory.decodeResource(getResources(), R.mipmap.bb);        }

10.自定义ViewGroup
新建类继承ViewGroup,两构造函数,复写onMeasure和onLayout方法

 public MyViewGroup(Context context) {        super(context);    }    public MyViewGroup(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);        height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);        setMeasuredDimension(width, height);        measureChildren(width, height);    }    //getHight即在界面上显示后的高度,getMeasuredHeight即还没在界面上显示,测量后的测量值    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {//changed横竖屏,左上右下        View view1=getChildAt(0);        if(view1!=null){            view1.layout(0,0,view1.getMeasuredWidth(),view1.getMeasuredHeight());        }        View view2=getChildAt(1);        if(view2!=null){            view2.layout(r-view2.getMeasuredWidth(),b-view2.getMeasuredHeight(),r,b);        }    }

10.自定义surfaceView
要新建一个线程实时刷新去画,线程中while(true),刷新频率24-30帧,sleep(40)即可,而自定义View中,更新用invalidate(),UI主线程自动调用onDraw方法。
新建类继承SurfaceView,实现SurfaceHolder.CallBack接口,由于要新建线程,也可实现Runnable接口,复写接口的方法,surfaceCreated开启线程,surfaceChanged(横竖屏等),surfaceDestroyed关闭线程false。

实现构造方法,构造方法中SurfaceHolder holder=getHolder(); holder.addcallback(this);

线程中while(true)
Canvas canvas=holder.lockCanvas();
用canvas开始画,先缓存到缓冲区中,调用下面的方法一起画在画布上。
holder.unlockCanvasAndPost(canvas);

0 0