Android 自定义View 启航 一般View定义

   Android应用程序使用View和ViewGroup来构建用户界面,它们都是继承自View类(或其子类)例如:Button、TextView、EditText等。各类View搭配上Style和Animation可以编织出非常丰富的UI,足以应付绝大部分的需求。但有时候我们也需要一些特别的View ,以带给用户与众不同的体验。

    在此我打算写一个大长篇都是关于android View的,主要内容为:SDK上部分文章翻译(英文水平有限尽请拍砖);自定义的View、android源代码分析、开源View代码分析;各类App应用的界面模仿;以理论+代码示例+实践 的方式指导本系列博文的撰写。

    ——因为本人水平有限,而且写系列经常虎头蛇尾,所以这个系列就不写总目录了。如果哪天您发现本系列不在更新,而我又开始了另一个“大长篇”,那么请扔鸡蛋吧。(但是我们不退票!)

    ——出于前车之鉴,本系列中的源码将不提供打包服务。

   言归正传,在我们编写android程序时一般是自定义以一个类继承自Activity 并且重写onCreate方法:

 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

setContentView()方法包含多个重载其中一个便是“setContentView(View view)”,也就是说可以直接通过一个View的实例来构建内容。我们尝试放入一个TextView,上面的代码变成了这样:

@Override
 public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
  // setContentView(R.layout.main);

      TextView sayHello = new TextView(this);
      sayHello.setText("Hello world! I'm a TextView.");
      setContentView(sayHello);
       
    }

运行这段代码,在模拟器上你应该可以看到以下结果:

截屏(2011-12-05 22_08_58).jpg

如此简单不是吗?好吧让我们再让它丰富点:

@Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  // setContentView(R.layout.main);
//  TextView sayHello = new TextView(this);
//  sayHello.setText("Hello world! I'm a TextView.");
  setContentView(new SayHello(this));
       
    }
 
 
 class SayHello extends View{

  public SayHello(Context context) {
   super(context);
  }

  @Override
  protected void onDraw(Canvas canvas) {
   super.onDraw(canvas);
   Paint mPaint=new Paint() ;
   mPaint.setTextSize(22f);
   mPaint.setColor(Color.RED);
   canvas.drawText("Hello world! I'm a TextView.", 0, 100, mPaint);
  }
 }

这次我们自定义了一个局部类SayHello 继承自View并且重写了 onDraw 方法(需要注意的是由于View没有无参构造函数所以我们为其指定实现哪一个构造函数)。在onDraw 方法中我们定义了一个Paint,现在你只需要理解它有绘画的功能即可,那么它要在哪里绘画呢?答案就是在Canvas上,可以把Canvas理解成画布。

现在我们设置mPaint的字体大小为22F  颜色为红色,然后在画布上写出“Hello world。。。”这几个红色的字,并且把onCreate里的setContentView 为setContentView(new SayHello(this));
最后在模拟器上你应该看到的是:

 截屏(2011-12-05 22_37_57).jpg

so cool! 不是吗?

不!不对,我们在Android的开发View不是这样的,它应该是通过 Xml.......@##¥%

好吧 让我们再把例子修改一下。

 首先我们将SayHello 类提取出来,并且将它放入一个单独的类文件中,接下来就是重点:我们需要添加另外的一些构造函数以便给View传递参数,最好你看到的SayHello 类应该是这样的:

public class SayHello extends View {
 
 public SayHello(Context context)
 {
  super(context);
 }

 public SayHello(Context context, AttributeSet attrs) {
  this(context, attrs,0);
 }
 
 public SayHello(Context context, AttributeSet attrs,int defStyle)
 {
  super(context, attrs, defStyle);
 }
 
 
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  Paint mPaint=new Paint() ;
  mPaint.setTextSize(22f);
  mPaint.setColor(Color.RED);
  canvas.drawText("Hello world! I'm a TextView.", 0, 100, mPaint);
 }
 

}

这里简单讲解一下新增的构造函数的作用,在新的构造函数中为View的构造函数传递了AttributeSet attrs,int defStyle两个参数,这代表着该View可以通过XML 来创建并且接受Style来设定样式。等到相关博文时会再具体讲解。

接下来,我们恢复Activity类里的onCreate方法让它看起来像这个样子:

@Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
   setContentView(R.layout.main);

       
    }

和一开始没啥两样对吧。

  最后我们需要去修改布局文件main 在文件里加入以下 xml标签:

 <com.××××.customview.SayHello
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >
    </com.××××.customview.SayHello>

(注意××××,代表SayHello类所在的包,这里需要的是全名)。

然后再次运行程序,你应该看到以下结果:

 截屏(2011-12-05 22_58_04).jpg

是不是和我们平常定义View时很像了?

你感觉得还不够,还缺乏些什么?

好吧,你很聪明,我们的Text应该是在XML上通过某个属性配置而成的,而不是写在代码里!

为了将SayHello的属性暴露到XMl上首先我们需要在res/value 文件夹下新建一个XMl文件,命名为:atts。

在里面添加如下代码:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="SayHello">
     <attr name="content" format="string"></attr>
     <attr name="text_color" format="color"></attr>
 </declare-styleable>
   
</resources>

 需要注意的是这里是没有智能提示的

然后我们需要修改SayHello类,还记得那个AttributeSet吗?我们将通过它来获取XML配置上的属性值。修改后的SayHello类代码是这样的:

private int mColor;
 private String mContent;

public SayHello(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  TypedArray typeArray = context.obtainStyledAttributes(attrs,
    R.styleable.SayHello);
  mColor=typeArray.getColor(R.styleable.SayHello_text_color, 0XFF00FF00);
  mContent=typeArray.getString(R.styleable.SayHello_content);
  
 }

@Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  Paint mPaint = new Paint();
  mPaint.setTextSize(22f);
  mPaint.setColor(mColor);
  canvas.drawText(mContent, 0, 100, mPaint);
 }

现在可以去XML上为哥哥属性添加值了,不过先别着急我们的得将命名空间告诉它。

在布局文件的根源是上(通常是Layout)添加: xmlns:SayHello="http://schemas.android.com/apk/res/com.XXXX.customview"

SayHello 可以为您任意想要定义的名字,它将作为属性的前缀使用就像android:Layout 一样而我们的为:SayHello:content,后半段http://schemas.android.com/apk/res/ 为固定值,紧接着的是你整个APP的包命名,你不知道自己包名称?赶去去 AndroidManifest.xml文件中看看吧(注意该包名需要保持和manifest中的 package 保持一致,否则会提示无法找到XML属性)。

最后我们终于可以在XML上定义自己想要的字体颜色的内容了:

<com.XXXX.customview.SayHello
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        SayHello:text_color="#1212f0"
        SayHello:content="this is a xml attr view">
    </com.XXXX.customview.SayHello>

 运行程序您应该会看到以下结果:

剪切板(2011-12-05 23_29_55).png

这就是我们View 一般的定义方式和过程。

——启航。

 //本笔记从 麦库中复制过来, 图片连不上,请见谅

原文地址:https://www.cnblogs.com/keyindex/p/2321027.html