android 之 custom view(一)

  android在两个基本布局类ViewViewGroup的基础上提供了成熟而又强大的构建UI组件模型。首先,平台包含了各种预先构建的ViewViewGroup,他们被称为widget和布局。你可以用他们构建你的UI

  一些可用的widget包括Button,TextView,EditText,ListView,CheckBox,RadioButton,Gallery,Spiner,和更多特殊用户的AutoComploteTextView,ImageSwitcher,TextSwitcher.

  一些可以使用的布局如LinearLayout,FramwLayout,RelativeLayout等。

  如果已有的widgets和布局不能满足你的要求,你可以创建你自己的View子类。如果你仅仅需要对一些已存在的widget所一些小小的调整,你可以创建他们的子类来重写一些方法。

  创建你自己的View的子类可以精确地控制界面元素的外观和功能。对于自定义的View组件,通常有下面几种处理方式:

  1.你可以创建一个完全自定义渲染的view类型,例如‘音量控制’旋钮使用2D图形,它类似于一个模拟电子控制。

  2.你可以组合一组view组件来构成一个新的、单一的组件。也许类似一个ComboBox(弹出列表和自由文本字段的组合),双窗口的控制选择器(),以此类推。

  3.你可以采用一种方式,类似覆盖EditText组件展示在屏幕上(记事本教程使用它效果不错,创建了一个具有线条的页面)

  4.你可以捕获其他的像按键事件和按照自定义的方式处理他们(事件)

  下面就说说如何创建自定义视图和应用程序中使用它们。一些常用的基本做法:

  1.扩展已有Viewclass或者View的子类。

  2.覆盖重写父类的一些方法,这些方法通常是以‘on'开头的方法。比如:onDraw,onMeasure(),onKeyDown,等。

  3.使用你的新的扩展类。一旦完成,你的新的扩展类可以使用在代替你扩展类的基类的地方。

  提示:扩展类通常作为使用它们的活动内的内部类,这样父类可以方方便的控制他。为了扩展它的使用范围,你同样可以设置它为public.

完全自定义组件:

  完全自定义组件可以创建你想要的任何图形组件。你可以根据你的想象(组件屏幕尺寸,组件的处理能力)创建你任何喜欢的(组件的)外观和行为。

创建一个完全自定义的组件步骤:

  a.继承View类;b.你可以提供一个构造方法,这个构造方法可以从XML文件获得组件的属性和参数。你可以定义你组件的属性和参数;c.你可以为你的组件创建自己的事件监听器,属性访问与修改,甚至更富在的组件行为;d.下面这个就比较重要了。你可以覆盖重写onMeasure(),onDraw()。默认情况下:onDraw()什么也不做,onMeasure()会设置一个100100的尺寸。e.你或许需要覆盖重写View其他的方法或者定义你自己的方法。

  

  掌握完全自定义组件最重要的两点:首先你了解组件被显示出来的所走的流程,也就是View类哪些方法被调用。其次就是属性与参数的定义。下图我自认为很重要,要好好理解:

 

  上面方法重要的两个:onDraw,onMeasure。那就好好说说他们吧。onDraw()方法传递了一个Canvas对象,这个对象你可以实现任何你想要的:2D图形,其他标准或者自定义的组件,文本风格,或者你其它你想要的(注意:这个并不适应3D图形。如果那样,你必须继承SurfaceView,在一个独立的线程绘画,参考GLSurfaceViewActivity sample).

   onMeasure就复杂了,简单的说就是决定你组件size的地方。这个决定的size不光可以是你组件本身size,还包括孩子组件的size(这个是很多人忽略的问题)。它有两个参数,这个两个参数是跟你的组件的layout_widthlayout_height有关系。在你计算出你的组件size之后,你就可以使用setMeasuredDimension()ok了。为什么呢,其实view的调用程序也就是:measure->onMeasure->setMeasuredDimension.

   下面就说说一些简单的例子吧:

  首先第一个就是samples里面的例子,因为是官方的,这个 必须说说,源代码如下:

LabelView.java
/**
* Example of how to write a custom subclass of View. LabelView
* is used to draw simple text views. Note that it does not handle
* styled text or right-to-left writing systems.
*
*/
public class LabelView extends View {
private Paint mTextPaint;
private String mText;
private int mAscent;

/**
* Constructor. This version is only needed if you will be instantiating
* the object manually (not from a layout XML file).
*
@param context
*/
public LabelView(Context context) {
super(context);
initLabelView();
}

/**
* Construct object, initializing with any attributes we understand from a
* layout file. These attributes are defined in
* SDK/assets/res/any/classes.xml.
*
*
@see android.view.View#View(android.content.Context, android.util.AttributeSet)
*/
public LabelView(Context context, AttributeSet attrs) {
super(context, attrs);
initLabelView();

TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.LabelView);

CharSequence s = a.getString(R.styleable.LabelView_text);
if (s != null) {
setText(s.toString());
}

// Retrieve the color(s) to be used for this view and apply them.
// Note, if you only care about supporting a single color, that you
// can instead call a.getColor() and pass that to setTextColor().
setTextColor(a.getColor(R.styleable.LabelView_textColor, 0xFF000000));

int textSize = a.getDimensionPixelOffset(R.styleable.LabelView_textSize, 0);
if (textSize > 0) {
setTextSize(textSize);
}

a.recycle();
}

private final void initLabelView() {
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(16);
mTextPaint.setColor(0xFF000000);
setPadding(3, 3, 3, 3);
}

/**
* Sets the text to display in this label
*
@param text The text to display. This will be drawn as one line.
*/
public void setText(String text) {
mText = text;
requestLayout();
invalidate();
}

/**
* Sets the text size for this label
*
@param size Font size
*/
public void setTextSize(int size) {
mTextPaint.setTextSize(size);
requestLayout();
invalidate();
}

/**
* Sets the text color for this label.
*
@param color ARGB value for the text
*/
public void setTextColor(int color) {
mTextPaint.setColor(color);
invalidate();
}

/**
*
@see android.view.View#measure(int, int)
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec),
measureHeight(heightMeasureSpec));
}

/**
* Determines the width of this view
*
@param measureSpec A measureSpec packed into an int
*
@return The width of the view, honoring constraints from measureSpec
*/
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);

if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text
result = (int) mTextPaint.measureText(mText) + getPaddingLeft()
+ getPaddingRight();
if (specMode == MeasureSpec.AT_MOST) {
// Respect AT_MOST value if that was what is called for by measureSpec
result = Math.min(result, specSize);
}
}

return result;
}

/**
* Determines the height of this view
*
@param measureSpec A measureSpec packed into an int
*
@return The height of the view, honoring constraints from measureSpec
*/
private int measureHeight(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);

mAscent = (int) mTextPaint.ascent();
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text (beware: ascent is a negative number)
result = (int) (-mAscent + mTextPaint.descent()) + getPaddingTop()
+ getPaddingBottom();
if (specMode == MeasureSpec.AT_MOST) {
// Respect AT_MOST value if that was what is called for by measureSpec
result = Math.min(result, specSize);
}
}
return result;
}

/**
* Render the text
*
*
@see android.view.View#onDraw(android.graphics.Canvas)
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent, mTextPaint);
}
}
attrs.xml
17 <resources>
18 <!-- These are the attributes that we want to retrieve from the theme
19 in app/PreferencesFromCode.java
-->
30 <declare-styleable name="LabelView">
31 <attr name="text" format="string" />
32 <attr name="textColor" format="color" />
33 <attr name="textSize" format="dimension" />
34 </declare-styleable>
35 </resources>

  这里它自定义了一个View组建LabelView.它只有三个属性:text,textColor,textSize,及相关方法。在第二个构造函数里,获取xml属性值做一些处理。然后就是onMeasure,onDraw,这个两个没有什么好说的,上面讲了的。


原文地址:https://www.cnblogs.com/slider/p/2286950.html