自定义View

Canvas画布的使用

默认坐标:
Canvas

Canvas类相当于一个矩形画布,默认0,0坐标是左上角。用到的坐标都是画布上的(即视图坐标系)。需要自定义View上的内容动起来呢,就是开外部接口,然后重绘(即重调用invalidate(),重绘,但Canvas上的条件一定要设置好变量)。
其常用方法有,draw( )方法最后一个参数都为Paint 对象:

  • drawRect(RectF rect,Paint paint);//在画布上绘制一个矩形;
    • react 对象为描述需要在Canvas上区域;
      参数一表示矩形左边的X坐标,余下三个同理。
save( );             

//此方法用于保存当前画布的状态,一般多用于旋转画布的时候

restore();

///此方法用于恢复画布,即恢复到save( )方法存入时的状态,但在画布上画的东西不会被撤销。

rotate(float degrees, float px, float py);

//此方法用于旋转画布,参数一为旋转的角度(正数为顺时针方向转,负数为逆时针),参数二,三画布旋转的轴点. 当画布旋转时呢,其的坐标也是跟着一起转动了,所以就意味着一定要此Canvas的中心坐标点来旋转,不然转了后内容会丢失。当确定点后,是以此点的上直线为O度. 当转动到相应的角度后,又以那个角度会0度。

一般来说,一次转动 对应一个内容绘制。下次转动并不会把上次绘制的内容也转动了.
多用于圆盘类的自定义View,确定一个地方的内容就可以转动绘制,省去多次确定坐标.

 RectF rectf =new RectF(float left,float top,float reight,float bottom);                
drawPath(Path path,Paint paint);

//在画布上绘制一个Path图形(即图像的轮廓),图形复杂时就用这个。

  • Path类常用方法用:

moveTo(float x,float y); //设置下次连接操作的坐标(移动的起点)。如不设置呢为Canvas的0,0 坐标。
lineTo(float x,float y);//设置上个点到此点用直线连接。
close();连接第一点到最后一个点,形成闭合。
更多内容查看此

drawBitmap(Bitmap bitmap,float left , float top , Paint paint) ;

//其实呢就是贴图。
因为一张图片长宽肯定是确定的,所以确定左上角的坐标就OK 了。

 drawLine(float startx , float starty , float stopx , float stopy , Paint paint) ;                               

//画线,当x坐标的起始和终止的坐标不变时,变化的为Y时,画出来的时竖线。反之横线。
当x和y都是变的,画出来的就是斜线。

drawPoint(float x, float y, Paint paint); 

//表示画点。

drawText(String text, float x, floaty, Paint paint) ;

//绘制文本,x,y坐标用于确定文字左上角的坐标。

drawOval(RectF oval, Paint paint);

//此为画椭圆,参数一用于确定椭圆外接矩形(用于确定椭圆能画多大).

drawCircle(float cx, float cy, float radius,Paint paint);

//此为画园,参数一二为确定圆的中心坐标。参数三为半径。

drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) ;

//画弧,参数一用于确定弧能画多大,参数二为弧的起始角度,参数三为绘制的角度,(弧会顺时针绘制)。参数四为是否把所画弧的开始点结束点连接到弧心,为false弧线,true就封。

Paint 画笔的使用

Paint对象呢为用于在Canvas上画东西的笔;

常用方法:

setAntiAlias(boolean aa);

此用于用于设置是否开启抗锯齿,为true呢为开启,false为不开启。

setStyle(Paint.Style style);

此用于设置画笔的风格。默认为 FILL(填满) ;
STROKE表示笔为空心,仅仅画边。FILL_AND_STROKE表示中心部分为空,外围填满。

setStrokeWidth(float width);

此方法用于设置当画笔为STROKE时,延伸出去的宽度。

setStrokeCap(Paint.Cap cap);

此方法用于设置一般用于弧线,设置头部和尾部是圆角,默认为直角.

setColor(int color);

此方法用于设置画笔的颜色.

setTextSize(float textSize) ;

滑动移动距离的计算

@Override 
public boolean onTouchEvent(MotionEvent event) {
        switch(event.getAction( ) ) {
                case MotionEvent.ACTION_DOWN:
                 lastx = (int) event.getX( );
                break;
                
                case MotionEvent.ACTION_MOVE:
               movex = (int) event.getX()-lastx;  //获取当前移动了多少距离;
                break;
                
                case MotionEvent.ACTION_UP:
                //处理输入的离开的事件.
                break;
        }
        return true;
}

如果在ACTION_MOVE中有重绘视图时,一定要最后重新获取当前的坐标,下次再执行到ACTION_MOVE状态才能正确计算偏移量,不然lastx一直是DOWN状态是的坐标.

X轴: 如果计算出移动的值为-值,那么就是向左滑,为正值,就是向右滑。

Y轴:如果计算出移动的值为-值,那么就是向上滑,为正值,就是向下滑。

自定义View 三大流程

通常要写自定义View呢

onMeasure( int widthMeasureSpec, int heightMeasureSpec) ; //测量;
onLayout(boolean changed, int left, int top, int right, int bottom) ; //布局;
onDraw(Canvas canvas);//绘制

onMeasure( )方法都得重写,因为系统默认对wrap_content的属性值处理是match_parent.所以想支持此属性就必须复写此方法来指定wrap_content的值。

@Override
protected  void  onMeasure(int widthMeasureSpec,int heightMeasureSpec) {
   setMeasuredDimension(measureHW(widthMeasureSpec,150) , measureHW(heightMeasureSpec,200));
}

private  int  widthMeasure(int  measureSpec , int defultV) {
   int result = defultV ;
   int mode = MeasureSpec.getMode(measureSpec);
   int size = MeasureSpec.getSize(measureSpec);
        
   if (mode == MeasureSpec.EXACTLY) {
         result = size;
   }else if (mode == MeasureSpec.AT_MOST) {
         result = Math.min(result , specSize);
   } 
   return result;
}
   

其中使用到的MeasurSpec类,为帮助测量View的, onMeasure( )方法中传递进入的值,是一个32位的int 值.解析出这个值就能获得此View的模式 和 大小.一般用到的两种模式

EXACTLY:即精确模式,View 的layout_height 和layout_width属性指定为精确数字或者match_parent时,View使用的就是EXACTLY模式。

AT_MOST: 即最大值模式,当 View 的layout_height 和 layout_width 属性指定为wrap_content.就是此模式 意指 控件的大小随内容变化,但是不能超过父View

一般来说的话,不写ViewGroup的话onLayout是不用i复写的,没有包含其他View所以也就不用计算其子View 的布局坐标。

onDraw( ) ,此方法就是最终显示到屏幕上的内容. 在绘制自定义View时呢,记得一定要把其拆分开,然后一个个的绘制 .

自定义属性

首先values文件下,新建attrs.xml的xml文件。声明资源类型为子标签为



    
        
        
        
        
        
        
        
        
        
    

//其中元素的name属性的值,就是此组自定义属性的容器名.

而 < attr > 元素表示的name属性表示View 控件的属性名,format属性表示支持的类型 .

要在布局文件中使用自定义属性呢,首先要要为这些自定义属性导入一个命名空间.

xmlns:app="http://schemas.android.com/apk/res-auto"

然后在具体的控件里,就能通过app:属性名 找到自定义属性了.

解析具体设置那些自定义属性,如下所示:

public TopBar(Context context, AttributeSet attrs) {
  super(context, attrs);
  getAttrs(attrs);
  setView(context);
}
 private void getAttrs(AttributeSet attrs) {
   TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.TopBar);
   mTitleText = ta.getString(R.styleable.TopBar_title);
   mTitleTextSize = ta.getDimension(R.styleable.TopBar_titleTextSize,10);
   mTitleTextColor = ta.getColor(R.styleable.TopBar_titleTextColor,0);
   mleftBackgound = ta.getDrawable(R.styleable.TopBar_leftBackground);
   mleftColor = ta.getColor(R.styleable.TopBar_leftTextColor,0);
   mleftText = ta.getString(R.styleable.TopBar_leftText);
   mRightColor = ta.getColor(R.styleable.TopBar_rightTextColor,0);
   mRightText = ta.getString(R.styleable.TopBar_rightText);
   mRightBackgound = ta.getDrawable(R.styleable.TopBar_rightBackground);
   ta.recycle();
}
 public void setView(Context context) {
    mleftButton = new Button(context);
    mRightButton = new Button(context);
    mTitle = new TextView(context);

    mTitle.setText(mTitleText);
    mTitle.setTextColor(mTitleTextColor);
    mTitle.setTextSize(mTitleTextSize);
    mTitle.setGravity(Gravity.CENTER);
    mTitleLP = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.MATCH_PARENT);
    mTitleLP.addRule(RelativeLayout.CENTER_IN_PARENT);

    mTitle.setLayoutParams(mTitleLP);

    mleftLP = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.MATCH_PARENT);
    mleftLP.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
    mleftButton.setText(mleftText);
    mleftButton.setTextColor(mleftColor);
    mleftButton.setBackground(mleftBackgound);
    mleftButton.setLayoutParams(mleftLP);

    mRightLp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.MATCH_PARENT);
    mRightLp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
    mRightButton.setText(mRightText);
    mRightButton.setTextColor(mRightColor);
    mRightButton.setBackground(mRightBackgound);
    mRightButton.setLayoutParams(mRightLp);


     addView(mTitle);
     addView(mRightButton);
     addView(mleftButton);
     setOnclik(mRightButton,mleftButton);
 }

通过构造函数提供的AttributeSet类的对象,getContext().obtainStyledAttributes(AttributeSet set, int[] attrs); 把AttributeSet对象解析到自定义属性 容器里(即对应R.styleable.TopBar) ,获得一个TypedArray类的对象,调用getString(R.styleable.TopBar_title, 0 ) ,其他属性类似,参数一为索引名,传入自定义属性中的名字就好(一定要以-连接),参数二为没有获取到值时的默认值。

你可能感兴趣的:(自定义View)