Apidemo学习 android 自定义View

哈哈,兄弟我终于自己写了一个view,不是网上那种简单的哦,还是有一定技术含量的,

我是通过学习ApiDemo(android自带的sample)里面LabelView实现的,

先谈谈学习过程,觉得一开始不应当盲目的动手做,应对想把原理搞明白,哪怕一个很小的View,也应当将各个细节弄清楚,

等这些搞定了,接下来的工作就是水道渠成了!


自定义一个View那必须继承View,

首先说说我的View是啥,恩,很简单,就是一个椭圆,其中可以设置4个参数,分别是top、left、right、bottom,应该很清楚吧,因为canvas.drawOval时用到了4个值,


首先得定义4个属性值,是我的View专有的,

建立attr.xml放到values下面

[java]  view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <resources>  
  3.      <declare-styleable name="RocketView">  
  4.         <attr name="ovalLeft" format="dimension" />  
  5.         <attr name="ovalTop" format="dimension" />  
  6.         <attr name="ovalRight" format="dimension" />  
  7.         <attr name="ovalBottom" format="dimension" />  
  8.     </declare-styleable>  
  9. </resources>  

然后写个RocketView

[java]  view plain copy
  1. package com.myos;  
  2.   
  3. import android.content.Context;  
  4. import android.content.res.TypedArray;  
  5. import android.graphics.Canvas;  
  6. import android.graphics.Color;  
  7. import android.graphics.Paint;  
  8. import android.graphics.RectF;  
  9. import android.util.AttributeSet;  
  10. import android.util.Log;  
  11. import android.view.View;  
  12. import android.view.View.MeasureSpec;  
  13.   
  14. public class RocketView extends View{  
  15.     private Paint mOvalPaint;  
  16.     private int mStrokeWidth = 2;  
  17.     private int padding = 3;  
  18.       
  19.     //椭圆参数  
  20.     private int mOval_l;  
  21.     private int mOval_t;  
  22.     private int mOval_r;  
  23.     private int mOval_b;  
  24.       
  25.       
  26.       
  27.     //构造  
  28.     public RocketView(Context context, AttributeSet attrs) {  
  29.         super(context, attrs);  
  30.         initRocketView();  
  31.           
  32.         TypedArray a = context.obtainStyledAttributes(attrs,  
  33.                 R.styleable.RocketView);  
  34.   
  35.         mOval_l = a.getDimensionPixelOffset(R.styleable.RocketView_ovalLeft, padding);    
  36.         mOval_t = a.getDimensionPixelOffset(R.styleable.RocketView_ovalTop, padding);    
  37.         mOval_r = a.getDimensionPixelOffset(R.styleable.RocketView_ovalRight, 100);    
  38.         mOval_b = a.getDimensionPixelOffset(R.styleable.RocketView_ovalBottom, 100);    
  39.   
  40.         a.recycle();  
  41.     }  
  42.   
  43.     private void initRocketView() {  
  44.         mOvalPaint = new Paint();  
  45.         mOvalPaint.setAntiAlias(true);  
  46.         mOvalPaint.setColor(Color.BLUE);  
  47.         mOvalPaint.setStyle(Paint.Style.STROKE);  
  48.         mOvalPaint.setStrokeWidth(mStrokeWidth);  
  49.         setPadding(padding,padding,padding,padding);  
  50.     }  
  51.       
  52.     public void setOvalRect(int l, int t, int r, int b){  
  53.         mOval_l = l + padding;  
  54.         mOval_t = t + padding;  
  55.         mOval_r = r;  
  56.         mOval_b = b;  
  57.         requestLayout();  
  58.         invalidate();  
  59.     }  
  60.     @Override  
  61.     protected void onDraw(Canvas canvas) {  
  62.         // TODO Auto-generated method stub  
  63.         super.onDraw(canvas);  
  64.         canvas.drawColor(Color.WHITE);  
  65.         // 绘制椭圆  
  66.         RectF re11 = new RectF(mOval_l, mOval_t, mOval_r, mOval_b);  
  67.         canvas.drawOval(re11, mOvalPaint);    
  68.           
  69. //      // 绘制圆形  
  70. //      canvas.drawCircle(mCircle_x, mCircle_y, mCircle_r, mPaint);  
  71.     }  
  72.       
  73.      /** 
  74.       * @see android.view.View#measure(int, int) 
  75.       */  
  76.      @Override  
  77.      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  78.          setMeasuredDimension(measureWidth(widthMeasureSpec),  
  79.                  measureHeight(heightMeasureSpec));  
  80.      }  
  81.   
  82.      /** 
  83.       * Determines the width of this view 
  84.       * @param measureSpec A measureSpec packed into an int 
  85.       * @return The width of the view, honoring constraints from measureSpec 
  86.       */  
  87.      private int measureWidth(int measureSpec) {  
  88.          int result = 0;  
  89.          int specMode = MeasureSpec.getMode(measureSpec);  
  90.          int specSize = MeasureSpec.getSize(measureSpec);  
  91.   
  92.          if (specMode == MeasureSpec.EXACTLY) {  
  93.              // We were told how big to be  
  94.              result = specSize;  
  95.          } else {  
  96.              // Measure the text  
  97.              result = mOval_r + getPaddingLeft()  
  98.                      + getPaddingRight();  
  99.              if (specMode == MeasureSpec.AT_MOST) {  
  100.                  // Respect AT_MOST value if that was what is called for by measureSpec  
  101.                  result = Math.min(result, specSize);  
  102.              }  
  103.          }  
  104.            
  105.          return result;  
  106.      }  
  107.   
  108.      /** 
  109.       * Determines the height of this view 
  110.       * @param measureSpec A measureSpec packed into an int 
  111.       * @return The height of the view, honoring constraints from measureSpec 
  112.       */  
  113.      private int measureHeight(int measureSpec) {  
  114.          int result = 0;  
  115.          int specMode = MeasureSpec.getMode(measureSpec);  
  116.          int specSize = MeasureSpec.getSize(measureSpec);  
  117.   
  118.          if (specMode == MeasureSpec.EXACTLY) {  
  119.              // We were told how big to be  
  120.              result = specSize;  
  121.          } else {  
  122.              // Measure the text (beware: ascent is a negative number)  
  123.              result = mOval_b + getPaddingTop()  
  124.                      + getPaddingBottom();  
  125.              if (specMode == MeasureSpec.AT_MOST) {  
  126.                  // Respect AT_MOST value if that was what is called for by measureSpec  
  127.                  result = Math.min(result, specSize);  
  128.              }  
  129.          }  
  130.            
  131.          return result;  
  132.      }  
  133. }  

在构造中getDimensionPixelOffset检索出一个属性值,没有的话就使用第2个参数做默认值,

可以在布局xml中初始化这个属性值,下面是我main.xml

[java]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:app="http://schemas.android.com/apk/res/com.myos"  
  4.     android:orientation="vertical"  
  5.     android:layout_width="fill_parent"  
  6.     android:layout_height="fill_parent"  
  7.     >  
  8.       
  9.     <TextView    
  10.         android:layout_width="wrap_content"   
  11.         android:layout_height="wrap_content"   
  12.         android:text="@string/hello"  
  13.         />  
  14.       
  15.     <com.myos.RocketView  
  16.         app:ovalLeft="0dp"  
  17.         android:id="@+id/rv"  
  18.         android:layout_width="wrap_content"  
  19.         android:layout_height="wrap_content" />  
  20.       
  21.   
  22. </LinearLayout>  
我这里没啥用处,仅仅试一下,待扩展属性时再说,说明一下xmlns:app中app可以随便命名的,这个android的规矩还真多

另外构造函数中onMeasure很重要的,onDraw很明显就是画椭圆了,android在画的时候呢,会去先测量,需要我们来提供View的宽和高,

大家都知道wrap_content、fill_parent,测量时会有3种模式,分别是UNSPECIFIED、EXACTLY、AT_MOST,

当使用

wrap_content时就是AT_MOST模式,fill_parent就是EXACTLY模式,可以看看官方文档:

http://developer.android.com/guide/topics/ui/how-android-draws.html

相信研读一下代码就明白了

RocketView定义好了,接下来就是使用了

[java]  view plain copy
  1. package com.myos;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5.   
  6. public class MainActivity extends Activity {  
  7.     RocketView mRocketView;  
  8.     /** Called when the activity is first created. */  
  9.     @Override  
  10.     public void onCreate(Bundle savedInstanceState) {  
  11.         super.onCreate(savedInstanceState);  
  12.         setContentView(R.layout.main);  
  13.           
  14.         mRocketView = (RocketView)findViewById(R.id.rv);  
  15.         mRocketView.setOvalRect(00500100);  
  16.     }  
  17. }  

可以通过setOvalRect函数来动态调整椭圆的大小!

下面是运行效果,ko啦!


基于Python的天气预测与可视化(完整源码+说明文档+数据),个人经导师指导并认可通过的高分设计项目,评审分99分,代码完整确保可以运行,小白也可以亲自搞定,主要针对计算机相关专业的正在做大作业的学生和需要项目实战练习的学习者,可作为毕业设计、课程设计、期末大作业,代码资料完整,下载可用。 基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基于Python的天气预测与可视化(完整源码+说明文档+数据)基
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值