精华内容
下载资源
问答
  • 安卓自定义控件

    2017-06-16 09:24:19
    安卓自定义控件## 安卓自定义控件 自定义步骤 view工作原理 自定义View的属性 重写构造方法自定义步骤 了解View的工作原理 编写继承自View的子类 为自定义View类增加属性 绘制控件 响应用户消息 自定义回调...

    安卓自定义控件

    ## 安卓自定义控件
    自定义步骤
    view工作原理
    自定义View的属性
    重写构造方法

    自定义步骤

        了解View的工作原理
    编写继承自View的子类
    为自定义View类增加属性
    绘制控件
    响应用户消息
    自定义回调函数
    

    view工作原理

    Android系统的视图结构的设计也采用了组合模式,即View作为所有图形的基类,Viewgroup对View继承扩展为视图容器类。

    View定义了绘图的基本操作
    基本操作由三个函数完成:measure()、layout()、draw(),其内部又分别包含了onMeasure()、onLayout()、onDraw()三个子方法。

    具体操作如下:

    1. measure操作

    measure操作主要用于计算视图的大小,即视图的宽度和长度。在view中定义为final类型,要求子类不能修改。measure()函数中又会调用下面的函数:

    (1)onMeasure(),视图大小的将在这里最终确定,也就是说measure只是对onMeasure的一个包装,子类可以覆写onMeasure()方法实现自己的计算视图大小的方式,并通过setMeasuredDimension(width, height)保存计算结果。

    2. layout操作

    layout操作用于设置视图在屏幕中显示的位置。在view中定义为final类型,要求子类不能修改。layout()函数中有两个基本操作:

    (1)setFrame(l,t,r,b),l,t,r,b即子视图在父视图中的具体位置,该函数用于将这些参数保存起来;

    (2)onLayout(),在View中这个函数什么都不会做,提供该函数主要是为viewGroup类型布局子视图用的;

    3. draw操作

    draw操作利用前两部得到的参数,将视图显示在屏幕上,到这里也就完成了整个的视图绘制工作。子类也不应该修改该方法,因为其内部定义了绘图的基本操作:

    (1)绘制背景;

    (2)如果要视图显示渐变框,这里会做一些准备工作;

    (3)绘制视图本身,即调用onDraw()函数。在view中onDraw()是个空函数,也就是说具体的视图都要覆写该函数来实现自己的显示(比如TextView在这里实现了绘制文字的过程)。而对于ViewGroup则不需要实现该函数,因为作为容器是“没有内容“的,其包含了多个子view,而子View已经实现了自己的绘制方法,因此只需要告诉子view绘制自己就可以了,也就是下面的dispatchDraw()方法;

    (4)绘制子视图,即dispatchDraw()函数。在view中这是个空函数,具体的视图不需要实现该方法,它是专门为容器类准备的,也就是容器类必须实现该方法;

    (5)如果需要(应用程序调用了setVerticalFadingEdge或者setHorizontalFadingEdge),开始绘制渐变框;

    (6)绘制滚动条;
    从上面可以看出自定义View需要最少覆写onMeasure()和onDraw()两个方法。
    自定义View的属性.

    首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式

        <?xml version="1.0" encoding="utf-8"?>  
        <resources>  
    
    <attr name="titleText" format="string" />  
    <attr name="titleTextColor" format="color" />  
    <attr name="titleTextSize" format="dimension" />  
    
    <declare-styleable name="CustomTitleView">  
        <attr name="titleText" />  
        <attr name="titleTextColor" />  
        <attr name="titleTextSize" />  
    </declare-styleable>  
    
        </resources>  
    

    我们定义了字体,字体颜色,字体大小3个属性,format是值该属性的取值类型,然后在布局中声明我们的自定义View

    xmlns:tools="http://schemas.android.com/tools"  
    xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent" >  
    
    <com.example.customview.view.CustomTitleView  
        android:layout_width="200dp"  
        android:layout_height="100dp"  
        custom:titleText="3712"  
        custom:titleTextColor="#ff0000"  
        custom:titleTextSize="40sp" />  
    
        </RelativeLayout>  
    

    在View的构造方法中,获得我们的自定义的样式

    private int mTitleTextColor;  
    private int mTitleTextSize;  
    private Rect mBound;  
    private Paint mPaint;  
    
    public CustomTitleView(Context context, AttributeSet attrs)  
    {  
        this(context, attrs, 0);  
    }  
    
    public CustomTitleView(Context context)  
    {  
        this(context, null);  
    }  
    
    /** 
     * 获得我自定义的样式属性 
     *  
     * @param context 
     * @param attrs 
     * @param defStyle 
     */  
    public CustomTitleView(Context context, AttributeSet attrs, int defStyle)  
    {  
        super(context, attrs, defStyle);  
        /** 
         * 获得我们所定义的自定义样式属性 
         */  
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyle, 0);  
        int n = a.getIndexCount();  
        for (int i = 0; i < n; i++)  
        {  
            int attr = a.getIndex(i);  
            switch (attr)  
            {  
            case R.styleable.CustomTitleView_titleText:  
                mTitleText = a.getString(attr);  
                break;  
            case R.styleable.CustomTitleView_titleTextColor:  
                // 默认颜色设置为黑色  
                mTitleTextColor = a.getColor(attr, Color.BLACK);  
                break;  
            case R.styleable.CustomTitleView_titleTextSize:  
                // 默认设置为16sp,TypeValue也可以把sp转化为px  
                mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(  
                        TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));  
                break;  
            }  
        }  
        a.recycle();  
        /** 
         * 获得绘制文本的宽和高 
         */  
        mPaint = new Paint();  
        mPaint.setTextSize(mTitleTextSize);  
        // mPaint.setColor(mTitleTextColor);  
        mBound = new Rect();  
        mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);  
    }
    

    重写构造方法

    默认的布局文件调用的是两个参数的构造方法,所以记得让所有的构造调用我们的三个参数的构造,我们在三个参数的构造中获得自定义属性。

    重写onDraw,onMesure调用系统提供的:

        @Override  
          protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
    {  
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
    }  
    
    @Override  
    protected void onDraw(Canvas canvas)  
    {  
        mPaint.setColor(Color.YELLOW);  
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);  
    
        mPaint.setColor(mTitleTextColor);  
        canvas.drawText(mTitleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);  
    } 
    

    系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。

    所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法”:

    重写之前先了解MeasureSpec的specMode,一共三种类型:

    EXACTLY:一般是设置了明确的值或者是MATCH_PARENT

    AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT

    UNSPECIFIED:表示子布局想要多大就多大,很少使用

    下面是我们
    重写onMeasure代码:

        @Override  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
    {  
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);  
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);  
    int width;  
    int height ;  
    if (widthMode == MeasureSpec.EXACTLY)  
    {  
        width = widthSize;  
    } else  
    {  
        mPaint.setTextSize(mTitleTextSize);  
        mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);  
        float textWidth = mBounds.width();  
        int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());  
        width = desired;  
    }  
    
      if (heightMode == MeasureSpec.EXACTLY)  
    {  
        height = heightSize;  
    } else  
    {  
        mPaint.setTextSize(mTitleTextSize);  
        mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);  
        float textHeight = mBounds.height();  
        int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());  
        height = desired;  
    }  
    
    
    
    setMeasuredDimension(width, height);  
    

    重写onDraw()

    protected void onDraw(Canvas canvas)  
    {  
        mPaint.setColor(Color.YELLOW);  
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);  
    
        mPaint.setColor(mTitleTextColor);  
        canvas.drawText(mTitleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);  
    }  
    

    作者:施彬彬:原文地址

    展开全文
  • 安卓自定义view全解安卓自定义view在本文的示例中,我们使用view基类的基本函数进行了属性设置,在onDraw函数中使用Canvas进行绘图,在onMeasure函数中调整控件大小,并且重写了onKeyDown、onKeyUp、...
    
        ad1.jpg
    

    全栈工程师开发手册 (作者:栾鹏)

    安卓教程全解

    安卓自定义view全解。

    view类包含如下函数。可供重写。

    onFinishInflate() 回调方法,当应用从XML加载该组件并用它构建界面之后调用的方法
    onMeasure() 检测View组件及其子组件的大小
    onLayout() 当该组件需要分配其子组件的位置、大小时
    onSizeChange() 当该组件的大小被改变时
    onDraw() 当组件将要绘制它的内容时
    onKeyDown 当按下某个键盘时
    onKeyUp 当松开某个键盘时
    onTrackballEvent 当发生轨迹球事件时
    onTouchEvent 当发生触屏事件时
    onWindowFocusChanged(boolean) 当该组件得到、失去焦点时
    onAtrrachedToWindow() 当把该组件放入到某个窗口时
    onDetachedFromWindow() 当把该组件从某个窗口上分离时触发的方法
    onWindowVisibilityChanged(int): 当包含该组件的窗口的可见性发生改变时触发的方法

    安卓自定义view

    在本文的示例中,我们使用view基类的基本函数进行了属性设置,在onDraw函数中使用Canvas进行绘图,在onMeasure函数中调整控件大小,并且重写了onKeyDown、onKeyUp、onTrackballEvent、onTouchEvent函数监听用户事件。

    public class UI_View extends View {  
    	
    	  // 使用代码创建时必须的构造函数
    	  public UI_View(Context context) {
    	    super(context);
    	    init();
    	  }
    
    	  //使用资源文件进行填充时必须的构造函数
    	  public UI_View (Context context, AttributeSet attrs) {
    	    super(context, attrs);
    	    init();
    	  }
    	  
    	  // 使用资源文件进行填充时必须的构造函数
    	  public UI_View (Context context, AttributeSet ats, int defaultStyle) {
    	    super(context,ats,defaultStyle);
    	    init();
    	  }
    	  
    	  //进行控件初始化
    	  private void init(){
    		  this.setBackgroundColor(Color.GREEN);   //设置背景颜色
    		  this.setX(100);   //设置x
    		  //...还有一大堆自己控制
    	  }
    	  
    	  //绘制自定义控件
    	  @Override
    	  protected void onDraw(Canvas canvas) {
    	    // 在上次对onMeasure方法调用的基础上获得控件的大小
    	    int height = getMeasuredHeight();
    	    int width = getMeasuredWidth();
    
    	    //找出控件的中心
    	    int px = width/2;
    	    int py = height/2;
    
    	    // 创建新的画刷,注意:由于效率的原因,这项工作应该在视图的构造函数中完成
    	    Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    	    mTextPaint.setColor(Color.RED);    //设置文字颜色
    	    mTextPaint.setTextSize(40);       //设置文字大小
    	    mTextPaint.setStrokeWidth(3);     //设置线宽   
    	    mTextPaint.setTextAlign(Align.LEFT);  //设置对齐方式
    	    //定义字符串
    	    String displayText = "Hello World!";
    
    	    //计算文本字符串的宽度
    	    float textWidth = mTextPaint.measureText(displayText);
    
    	    //在控件的中心绘制文本字符串
    	    canvas.drawText(displayText, px-textWidth/2, py, mTextPaint);
    	    Log.v("自定义view", "绘制控件");
    	  }
    	  
    	 
    	  //onMeasure用来调整控件大小,默认为100*100
    	  @Override
    	  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    	    int measuredHeight = measureHeight(heightMeasureSpec);
    	    int measuredWidth = measureWidth(widthMeasureSpec);
    	    //必须调用setMeasuredDimension,否则在布局控件的时候会造成运行时异常
    	    setMeasuredDimension(measuredHeight, measuredWidth);
    	    Log.v("自定义view", "调整大小");
    	  }
    
    	  private int measureHeight(int measureSpec) {
    	    int specMode = MeasureSpec.getMode(measureSpec);
    	    int specSize = MeasureSpec.getSize(measureSpec);
    
    	    //  如果不指定限制,就是默认大小
    	    int result = 200;
    
    	    if (specMode == MeasureSpec.AT_MOST) {
    	      //计算控件在这个最大尺寸范围内的理想大小,如果控件填充了可用空间,则返回外边界
    	      result = specSize;
    	    } else if (specMode == MeasureSpec.EXACTLY) {
    	      // 如果控件可以放置在这个边界内,则返回该值
    	      result = specSize;
    	    }
    	    return result;
    	  }
    
    	  private int measureWidth(int measureSpec) {
    	    int specMode = MeasureSpec.getMode(measureSpec);
    	    int specSize = MeasureSpec.getSize(measureSpec);
    
    	    //如果不指定限制,就是默认的大小
    	    int result = 200;
    
    	    if (specMode == MeasureSpec.AT_MOST) {
    	      // 计算控件在这个最大的尺寸范围内的理想大小,如果控件填充了可用的空间,那么返回外边界
    	      result = specSize;
    	    } else if (specMode == MeasureSpec.EXACTLY) {
    	      // 如果控件可以放置在这个边界内,则返回该值
    	      result = specSize;
    	    }
    	    return result;
    	  }
    	  
    	  //用户交互事件
    	  @Override
    	  public boolean onKeyDown(int keyCode, KeyEvent keyEvent) {
    		  //如果事件得到处理,返回true
    		  Log.v("自定义view", "按键按下");
    		  return true;
    	  }
    
    	  @Override
    	  public boolean onKeyUp(int keyCode, KeyEvent keyEvent) {
    		  //如果事件得到处理,返回true
    		  Log.v("自定义view", "按键弹起");
    		  return true;
    	  }
    
    	  @Override
    	  public boolean onTrackballEvent(MotionEvent event ) {
    	    // 获得这个事件代表的动作类型
    	    int actionPerformed = event.getAction();
    	    Log.v("自定义view", event.toString());
    	    // 如果事件得到处理,返回true
    	    return true;
    	  }
    
    	  @Override
    	  public boolean onTouchEvent(MotionEvent event) {
    	    // 获得这个事件代表的动作类型
    	    int actionPerformed = event.getAction();
    	    Log.v("自定义view", event.toString());
    	    // 如果事件得到处理,返回true
    	    return true;
    	  }
    
    }
    

    将我们自定义的view添加到窗口中有两种方式

    1、在activity中将自定义view添加到窗口中

    LinearLayout linearLayout = (LinearLayout)findViewById(R.id.activity1_linearlayout1);
    UI_View myview = new UI_View(this);
    linearLayout.addView(myview);
    

    2、在xml布局文件中添加

    在xml中添加也可以设置view的基本属性。不过在view显示时还是会调用onMeasure函数中设置的控件大小。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/activity1_linearlayout1"
        android:orientation="vertical">
        
        <com.lp.app.ui.UI_View 
            android:id="@+id/activity1_ui_view1"
            android:layout_width="match_parent"
            android:layout_height="100px"
            />
    	
    </LinearLayout>
    
    展开全文
  • 安卓自定义倒计时View

    2020-03-25 18:28:48
    无论是我们继承系统View还是直接继承View,都需要对构造函数进行重写,构造函数有多个,至少要重写其中一个才行。如我们新建CountDownTextView继承AppCompatTextView public class CountDownTextView extends ...

    1继承View

    无论是我们继承系统View还是直接继承View,都需要对构造函数进行重写,构造函数有多个,至少要重写其中一个才行。如我们新建CountDownTextView继承AppCompatTextView

    public class CountDownTextView extends AppCompatTextView

    2 自定义属性

    Android系统的控件以android开头的都是系统自带的属性。为了方便配置自定义View的属性,我们也可以自定义属性值。
    Android自定义属性可分为以下几步:

    1. 自定义一个View
    2. 编写values/attrs.xml,在其中编写styleable和item等标签元素
    3. 在布局文件中View使用自定义的属性(注意namespace)
    4. 在View的构造方法中通过TypedArray获取
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="test">
            <attr name="counttime" format="integer" />
        </declare-styleable>
    </resources>

    <com.layout.CountDownTextView
            app:counttime="180"
           ></com.layout.CountDownTextView>

     

    public CountDownTextView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.test);
            long test_counttime = ta.getInteger(R.styleable.test_counttime, 120);
            TOTAL_TIME=test_counttime*1000;
            ta.recycle();
            Log.e(TAG, "test_counttime = " + TOTAL_TIME);
            
        }

    3定义倒计时

     public void startCountTime() {
            countDownTimer = new CountDownTimer(TOTAL_TIME, ONCE_TIME) {
                @Override
                public void onTick(long millisUntilFinished) {
                  
                   String value = String.valueOf((int) (millisUntilFinished / 1000));
                   setText("倒计时"+value +"秒后,返回首页");
                }
    
                @Override
                public void onFinish() {
                 };
            
            countDownTimer.start();
        }
    
    
        public void stopCountTime() {
        if(countDownTimer!=null){
            countDownTimer.cancel();
            countDownTimer=null;
            setText("倒计时120秒后,返回首页");
        }
    

     

    展开全文
  • 自定义View我们大部分时候只需重写两个函数:onMeasure()、onDraw()。onMeasure负责对当前View的尺寸进行测量,onDraw负责把当前这个View绘制出来。当然了,你还得写至少写2个构造函数:public MyView(Context ...

    1.自定义View介绍:
    自定义View我们大部分时候只需重写两个函数:onMeasure()、onDraw()。onMeasure负责对当前View的尺寸进行测量,onDraw负责把当前这个View绘制出来。当然了,你还得写至少写2个构造函数:

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

    关于onMeasure,我们为什么需要测量?
    我们平时写view的大小无非三种情况:而是wrap_content或者是match_parent或者指定大小,那么自定义view为什么还需要来测量宽高呢,我们知道将尺寸设置为“包住内容”和“填充父布局给我们的所有空间”,但是这两个设置并没有指定真正的大小,可是我们绘制到屏幕上的View必须是要有具体的宽高的,正是因为这个原因,我们必须自己去处理和设置尺寸。当然了,View类给了默认的处理,但是如果View类的默认处理不满足我们的要求,我们就得重写onMeasure函数啦~。这里举个例子,比如我们希望我们的View是个正方形,如果在xml中指定宽高为wrap_content,如果使用View类提供的measure处理方式,显然无法满足我们的需求。
    我们重写的onMeasure()函数是:

    protected void onMeasure(int widthMeasureSpec, int                         heightMeasureSpec)

    我们可以通过:

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);

    取得我们需要的测量模式和大小。
    其中测量模式有三种:

    测量模式 ——————– 表示意思
    UNSPECIFIED ————-父容器没有对当前View有任何限制,当前View可以任意取尺寸
    EXACTLY————— 当前的尺寸就是当前View应该取的尺寸
    AT_MOST————— 当前尺寸是当前View能取的最大尺寸

    而上面的测量模式跟我们的布局时的wrap_content、match_parent以及写成固定的尺寸有什么对应关系呢?

    match_parent—>EXACTLY。怎么理解呢?match_parent就是要利用父View给我们提供的所有剩余空间,而父View剩余空间是确定的,也就是这个测量模式的整数里面存放的尺寸。
    wrap_content—>AT_MOST。怎么理解:就是我们想要将大小设置为包裹我们的view内容,那么尺寸大小就是父View给我们作为参考的尺寸,只要不超过这个尺寸就可以啦,具体尺寸就根据我们的需求去设定。
    固定尺寸(如100dp)—>EXACTLY。用户自己指定了尺寸大小,我们就不用再去干涉了,当然是以指定的大小为主啦。

    1. 感受一下onMeasure的使用,假设我们要实现这样一个效果:将当前的View以正方形的形式显示,即要宽高相等,并且默认的宽高值为100像素。就可以这些编写:

    private int getMySize(int defaultSize, int measureSpec) {
            int mySize = defaultSize;
    
            int mode = MeasureSpec.getMode(measureSpec);
            int size = MeasureSpec.getSize(measureSpec);
    
            switch (mode) {
                case MeasureSpec.UNSPECIFIED: {//如果没有指定大小,就设置为默认大小
                    mySize = defaultSize;
                    break;
                }
                case MeasureSpec.AT_MOST: {//如果测量模式是最大取值为size
                    //我们将大小取最大值,你也可以取其他值
                    mySize = size;
                    break;
                }
                case MeasureSpec.EXACTLY: {//如果是固定的大小,那就不要去改变它
                    mySize = size;
                    break;
                }
            }
            return mySize;
    }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int width = getMySize(100, widthMeasureSpec);
            int height = getMySize(100, heightMeasureSpec);
    
            if (width < height) {
                height = width;
            } else {
                width = height;
            }
    
            setMeasuredDimension(width, height);
    }

    我们设置一下布局

    <com.hc.studyview.MyView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:background="#ff0000" />
    

    看看使用了我们自己定义的onMeasure函数后的效果:
    自定义View
    这里写图片描述
    而如果我们不重写onMeasure,效果则是如下:
    这里写图片描述

    2. 重写onDraw开始画图
    我们要View显示一个圆形,由于我们在上面已经实现了宽高尺寸相等,下面就简单了:

    @Override
        protected void onDraw(Canvas canvas) {
            //调用父View的onDraw函数,因为View这个类帮我们实现了一些
            // 基本的而绘制功能,比如绘制背景颜色、背景图片等
            super.onDraw(canvas);
            int r = getMeasuredWidth() / 2;//也可以是getMeasuredHeight()/2,本例中我们已经将宽高设置相等了
            //圆心的横坐标为当前的View的左边起始位置+半径
            int centerX = getLeft() + r;
            //圆心的纵坐标为当前的View的顶部起始位置+半径
            int centerY = getTop() + r;
    
            Paint paint = new Paint();
            paint.setColor(Color.GREEN);
            //开始绘制
            canvas.drawCircle(centerX, centerY, r, paint);
    
    
        }

    这里写图片描述

    3. 使用自定义布局属性
    可以在布局文件中由用户写属性,
    自定义View的属性,首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。

    <?xml version="1.0" encoding="utf-8"?>  
    <resources>  
    
        <attr name="titleText" format="string" />  
        <attr name="titleTextColor" format="color" />  
        <attr name="titleTextSize" format="dimension" />  
    
        <declare-styleable name="CustomTitleView">  
            <attr name="titleText" />  
            <attr name="titleTextColor" />  
            <attr name="titleTextSize" />  
        </declare-styleable>  
    
    </resources>  

    或者这样写:

    <resources> 
    <declare-styleable name="CustomTitleView"> 
    <attr name="titleText" format="string" /> 
    <attr name="titleTextColor" format="color" /> 
    <attr name="titleTextSize" format="dimension" /> 
    
    </declare-styleable> 
    
    </resources>

    第一种写法可以提供共用属性的,当自定义view多时,很有用的。

    我们定义了字体,字体颜色,字体大小3个属性,format是值该属性的取值类型:一共有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;不清楚的可以google一把。
    然后在布局中声明我们的自定义View

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
        xmlns:tools="http://schemas.android.com/tools"  
        xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent" >  
    
        <com.example.customview01.view.CustomTitleView  
            android:layout_width="200dp"  
            android:layout_height="100dp"  
            custom:titleText="3712"  
            custom:titleTextColor="#ff0000"  
            custom:titleTextSize="40sp" />  
    
    </RelativeLayout>  
    

    一定要引入

    xmlns:custom=”http://schemas.android.com/apk/res/com.example.customview01”

    我们的命名空间,后面的包路径指的是项目的package
    然后在View的构造方法中,获得我们的自定义的样式

    /** 
         * 文本 
         */  
        private String mTitleText;  
        /** 
         * 文本的颜色 
         */  
        private int mTitleTextColor;  
        /** 
         * 文本的大小 
         */  
        private int mTitleTextSize;  
    
        /** 
         * 绘制时控制文本绘制的范围 
         */  
        private Rect mBound;  
        private Paint mPaint;  
    
        public CustomTitleView(Context context, AttributeSet attrs)  
        {  
            this(context, attrs, 0);  
        }  
    
        public CustomTitleView(Context context)  
        {  
            this(context, null);  
        }  
    
        /** 
         * 获得我自定义的样式属性 
         *  
         * @param context 
         * @param attrs 
         * @param defStyle 
         */  
        public CustomTitleView(Context context, AttributeSet attrs, int defStyle)  
        {  
            super(context, attrs, defStyle);  
            /** 
             * 获得我们所定义的自定义样式属性 
             */  
            TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyle, 0);  
            int n = a.getIndexCount();  
            for (int i = 0; i < n; i++)  
            {  
                int attr = a.getIndex(i);  
                switch (attr)  
                {  
                case R.styleable.CustomTitleView_titleText:  
                    mTitleText = a.getString(attr);  
                    break;  
                case R.styleable.CustomTitleView_titleTextColor:  
                    // 默认颜色设置为黑色  
                    mTitleTextColor = a.getColor(attr, Color.BLACK);  
                    break;  
                case R.styleable.CustomTitleView_titleTextSize:  
                    // 默认设置为16sp,TypeValue也可以把sp转化为px  
                    mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(  
                            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));  
                    break;  
    
                }  
    
            }  
            a.recycle();  
    
            /** 
             * 获得绘制文本的宽和高 
             */  
            mPaint = new Paint();  
            mPaint.setTextSize(mTitleTextSize);  
            // mPaint.setColor(mTitleTextColor);  
            mBound = new Rect();  
            mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);  
    
        }

    我们重写了3个构造方法,默认的布局文件调用的是两个参数的构造方法,所以记得让所有的构造调用我们的三个参数的构造,我们在三个参数的构造中获得自定义属性。

    更多高级用法参考:http://blog.csdn.net/huachao1001/article/details/51577291

    –>路要一步一步走,记住自己走过的路,不再犯同样的错误,才是真正的成长!欢迎指点、交流。<–

    展开全文
  • 开发自定义控件的步骤: ...6、自定义回调函数; 一、View的结构原理: Android系统的视图结构的设计也采用了组合的模式,即View作为所有图形的基类,Viewgroup对view继承扩展为视图容器类; View定义了...
  • 安卓自定义view总结1

    2016-04-12 20:20:12
    一直以来用了很多自定义view都没有好好总结,今天就总结总结: 第一个例子:验证码 思路:重写view: 1. values下创建文件attr.xml :... 2.1:重载构造函数的三种: public CustomTitleView(Context context);
  • 安卓自定义滑动按钮

    2015-03-06 16:33:21
    在很多时候我们看到在iphone手机应用中都有滑动开启和关闭这个功能,在android40以下的版本中且...第一步:创建一个打开关闭的状态接口函数OnChangedListener主要创建一个打开关闭状态的抽象方法OnChanged(boolean Ch
  • 最近看到注解类自定义,想自己试试,然后理一理加深印象。 第一步,创建一个注解类接口。包含三个函数,即布局文件id,长点击和点击事件。 /** * 自定义注解接口 */ @Target(ElementType.FIELD) @Retention...
  • 自定义View绘制流程函数调用链(简化版)一.自定义View分类1.自定义ViewGroup 自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件,大多继承自ViewGroup或各种Layout,包含有子View。2.自定义View...
  • 本章节为什么要叫进阶篇?(虽然讲的是基础内容),因为从本篇开始,将会逐渐揭开自定义View的神秘面纱,每一篇都将比上一篇内容更加深入,利用所学的知识能够制作更加炫酷...自定义View绘制流程函数调用链(简化版) ...
  • 这里自定义一个Sharedpreference 存储的工具类,包含多个sharedpreference的构造函数,和Editor 的存储方法函数。 public class SettingUtils { private static SharedPreferences sharedPreferences=null; ...
  • 安卓中角度(angle)与弧度(radian)的有关问题。 一.前言 1.为什么讲这个? 在我们自定义View,尤其是制作一些复杂炫酷的效果的时候,实际上是将一些简单的东西通过数学上精密的计算组合到一起形成的效果。 这其中...
  • 这个日志工具,主要是对原来的日志函数进行一层封装,在进行日志输出之前,进行一层判断,我们可以通过控制这层判断的级别,进而过滤输出,甚至将全部日志全部过滤掉,不输出日志。public class ...
  • 我们自定义View,或者是制造一些炫酷的视觉效果时,其实是将一些简单的东西用数学的精密计算组合到一起形成的视觉效果。 这会涉及到画布的相关操作,以及一些正余弦函数的计算等,而且这些内容就会用到一些角度、...
  • 安卓类内定义一个静态实例。用静态实例再调用类内其他非静态函数。实例如下代码 package com.example.libforunity; import android.app.Fragment; public class MainActivity extends Fragment { public static ...
  • 在我们自定义View,尤其是制作一些复杂炫酷的效果的时候,实际上是将一些简单的东西通过数学上精密的计算组合到一起形成的效果。 这其中可能会涉及到画布的相关操作(旋转),以及一些正余弦函数的计算等,...

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 176
精华内容 70
关键字:

安卓自定义函数