自定义View 一 (继承VIew重写onDraw方法)

项目:具有圆形效果的自定义View

一、继承View并重写onDraw方法

public class CircleView extends View{
    private static final int COLOR = Color.RED;
    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private int mWidth = 0;
    private int mHeight = 0;

    public CircleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CircleView(Context context) {
        super(context);
        init();
    }

    public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        mPaint.setColor(COLOR);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //获取当前View的宽/高
        mWidth = getMeasuredWidth();
        mHeight = getMeasuredHeight();
        //获取半径
        int radium = Math.min(mWidth,mHeight)/2;
        //画圆
        canvas.drawCircle(mWidth/2,mHeight/2,radium,mPaint);
    }

}

CircleView

在xml中测试margin发现可以用,说明margin是由父容器控制的(想起measureChildMarginLayout源码)

但是wrap_content和padding都不生效。

二、让wrap_content生效

根据上一章View的工作原理:①、重写onMeasure方法  ②、给CircleView设定一个固定的宽高

//设定wrap_content时候的宽度
private static final int AT_WIDTH = 30;
private static final int AT_HEIGHT = 30;

//重写onMeasure()方法
@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //获取子View的范围
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
       //判断当属性为wrap_content的时候
        if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(AT_WIDTH,AT_HEIGHT);
        }
        else if (widthMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(AT_WIDTH,heightSize);
        }
        else if (heightMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(widthSize,AT_HEIGHT);
        }
        else {
            super.onMeasure(widthMeasureSpec,heightMeasureSpec);
        }
    }    

三、解决无法padding的问题

原理:只需要在onDraw中,获取padding的参数就可以了

//重写onDraw方法
 protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //获取padding
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingTop = getPaddingTop();
        int paddingBottom = getPaddingBottom();
        //获取当前View的宽/高 减去padding
        mWidth = getMeasuredWidth() - paddingLeft - paddingRight;
        mHeight = getMeasuredHeight() - paddingTop - paddingBottom;
        //获取半径
        int radium = Math.min(mWidth,mHeight)/2;
        //画圆
        canvas.drawCircle(paddingLeft+mWidth/2,paddingTop - mHeight/2,radium,mPaint);
    }

CircleView

四、自定义属性

步骤:①、在values目录中创建xml文件名,文件名必须以attr_开头。②、内容的编写:<declare-styleadable>标签中:name代表自定义属性(该为CircleView类)

<attr>标签中 name代表之后使用的属性名(circle_color),format代表格式(color)

<resources>
    <declare-styleable name="CircleView">
        <attr name="color_circle" format="color"/>
    </declare-styleable>
</resources>

attr_circleview

步骤③、在布局文件中使用自定义属性  必须在schemas声明:xmlns:app="http://schemas.android.com/apk/res-auto" 其中app名字可以随便替换。

但是circleView中自定义属性名的前缀必须是和这里一致(一般习惯使用app)

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    //这一段必须要加    app名字可以替换    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.maikefengchao.circleview.MainActivity">

    <com.maikefengchao.circleview.CircleView
        android:layout_width="80dp"
        android:layout_height="80dp"        //前缀与添加的声明前缀一致        app:color_circle="#9999"/>
</LinearLayout>

步骤④:在CircleView中获取自定义属性参数

//在构造方法中使用
 public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //加载自定义属性集合CircleView
        TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.CircleView);
        //解析集合中的circle_circle,设置默认颜色
        mColor = a.getColor(R.styleable.CircleView_color_circle,Color.RED);
        init();
    }

全部代码:(P209 ①)

时间: 2024-10-11 09:55:27

自定义View 一 (继承VIew重写onDraw方法)的相关文章

Swing自定义JScrollPane的滚动条设置,重写BasicScrollBarUI方法

Swing自定义JScrollPane的滚动条设置,重写BasicScrollBarUI方法 摘自:https://blog.csdn.net/qq_31635851/article/details/80986870 1.自定义BasicScrollBarUI类 1 import java.awt.AlphaComposite; 2 import java.awt.Color; 3 import java.awt.Dimension; 4 import java.awt.GradientPain

自定义View中为什么需要重写onMeasure()方法?

不实现OnMeasure()方法的时候 首先自定义一个简单的view: public class myView extends View { public myView(Context context) { super(context); } public myView(Context context, AttributeSet attrs) { super(context, attrs); } } 在布局中使用: <RelativeLayout xmlns:android="http:/

C#继承,重写虚方法的使用笔记

一,如下例子 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DemoTest { class Program { static void Main(string[] args) { B a = new B(); } } public class A { public A() { Say(); } protected virtual void Say()

自定义视图(继承View)

前言 Android提供了丰富的控件,但是有时候还是不能满足自己的需求,这时候就需要自定义视图了,自定义视图分为几种,一种为继承为View的,一种为继承于ViewGroup的.继承于View的需要我们自己去绘制控件,继承于ViewGroup的可以组织已有的控件,下面就先介绍下继承于View的情况. 效果图 下面就是自定义了一个简单的圆形图来介绍整个的绘制过程,如下所示 概述 绘制一个控件需要绘制两部分内容,一是尺寸,二是内容,这通过两个方法来进行绘制,一个是onMeasure.一个是onDraw

自定义View(二)--继承自ViewGroup

自定义View包括很多种,上一次随笔中的那一种是完全继承自View,这次写的这个小Demo是继承自ViewGroup的,主要是将自定义View继承自ViewGroup的这个流程来梳理一下,这次的Demo中自定义了一个布局的效果,并且这个自定义布局中包含布局自己的属性,布局中的控件也包含只属于这个布局才具有的自定义属性(类似于layout_weight只存在于LinearLayout中,只有LinearLayout中的控件可以使用一样).话不多说,先看效果图: 其中红色的部分是自定义的ViewGr

自定义控件之直接继承View创建全新视图(二)

自定义控件我们上一节探讨了一种最简单的自定义是直接继承View的子类,实现控件的不同UI视图展示及功能的拓展,在学习新知识前可以温习下之前所学知识-自定义控件之对现有控件拓展(一). ok,在回顾了之前所学的知识之后,现在我们来学习稍微复杂点的自定义控件:今天我们实现一个直接继承于View的全新控件.大家都知道音乐播放器吧,在点击一首歌进行播放时,通常会有一块区域用于显示音频条,我们今天就来学习下,播放器音频条的实现. 首先我们还是先定义一个类,直接继承于View,并重写它的构造方法,并初始化一

Android View系列一: View基础知识

1.什么是View View是Android中所有控件的基类,是一种界面层的控件的一种抽象,它代表了一个控件,除了View,还有ViewGroup(控件组),ViewGroup内部包含了许多控件,即一组View.ViewGroup继承View. 2.View的位置参数 View的位置由四个顶点决定:top left right bottom top:是左上角纵坐标. left:是左上角横坐标. right:是右下角横坐标. bottom:是右下角纵坐标. 这些坐标都是相对于View的父容器来说的

面向对象(继承、重写、多态)以及异常处理

一.继承(单继承多继承继承:即可以继承多个父类) 目标: 实现代码的重用,相同的代码不需要重复的编写. class Human: #创建一个类 def eat(self): print('chi') def drink(self): print('he') def la(self): print('la') def sa(self): #有吃喝拉撒四种方法 print('sa') class Man(Human): #再创建一个类Man,以Human做父类,就继承了Human的四种方法 def

Android 自定义View需要重写ondraw()等方法

Android  自定义View需要重写ondraw()等方法,这篇博客给大家说说自定义View的写法,需要我们继承View,然后重写一些 方法,方法多多,看你需要什么方法 首先写一个自定义的View 继承View package com.example.engineerjspview; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import and