Android总结之视图View总结&自定义View

视图View总结&自定义View

        • 1.Android中视图View按是否可以包裹子视图划分为2类
          • 1.1.基类不是ViewGroup且继承自View的类
          • 1.2.ViewGroup及其子类
        • 2.Android中View的生命周期方法
        • 3.自定义View
          • 3.1.res/values下添加attr.xml用于TimerChooser自定义属性
          • 3.2.定义子类继承View
            • 3.2.1.定义构造方法,参考android.view.View.java中构造方法
            • 3.2.2.重写onMeasure方法,参考android.view.View.java中onMeasure方法
            • 3.2.3.重写onDraw方法,参考android.view.View.java中onDraw方法
            • 3.2.4.设置监听器定义TimerChooser值(小时和分钟)改变的回调方法
            • 3.2.5.重写onTouchEvent方法
          • 3.3.layout布局文件下添加TimerChooser视图
          • 3.4.在Activity中使用TimerChooser视图并使用监听器打印小时分钟值的日志
        • 4.自定义ViewGroup

1.Android中视图View按是否可以包裹子视图划分为2类

1.1.基类不是ViewGroup且继承自View的类
  • 不可以包裹子视图
  • 包括一些常见的子类,如文本TextView、开关Switch、单选RadioButton、图片ImageView、多选CheckBox、按钮Button、输入EditText
1.2.ViewGroup及其子类
  • 包裹子视图
  • 继承自View,实现了ViewParentViewManager接口
  • 直接子类包含下面5个视图布局类(AbsoluteLayout已过时,官方不推荐使用)
layout remark
LinearLayout 在单列中水平排列或在单行中垂直排列其他视图的布局
TableLayout 将子级排列成行和列的布局
FrameLayout 在屏幕上屏蔽一个区域以显示单个项目
RelativeLayout 在这种布局中,子对象的位置可以相互描述或与父对象描述。
GridLayout 将其子项放置在矩形网格中的布局
AbsoluteLayout 允许您指定其子级的精确位置(X/Y坐标)的布局

2.Android中View的生命周期方法

Category Method Description
创建 Constructors 应用layout布局文件中的属性
onFinishInflate() 在视图及其所有子视图都已从XML注入后调用
布局 onMeasure() 调用以确定此视图及其所有子视图的大小要求
onLayout() 当此视图应为其所有子视图指定大小和位置时调用
onSizeChanged() 当此视图的大小改变时调用
画图 onDraw() 在视图应呈现其内容时调用
事件处理 onKeyDown() 在发生硬件事件时调用
onKeyUp() 当发生硬件启动事件时调用
onTrackballEvent() 当轨迹球运动事件发生时调用
onTouchEvent() 当触摸屏运动事件发生时调用
焦点 onFocusChanged() 当视图获得或失去焦点时调用
onWindowFocusChanged() 当包含视图的窗口获得或失去焦点时调用
依附 onAttachedToWindow() 当视图附在到窗口时调用
onDetachedFromWindow() 当视图与其窗口分离时调用
onWindowVisibilityChanged() 当包含视图的窗口的可见性发生改变时调用

3.自定义View

本文主要及介绍的是自定义View(继承android.view.View),一个小时分钟选择器TimerChooser,地址:https://github.com/15045120/iAlarmClock,效果图如下:
Android总结之视图View总结&自定义View_第1张图片
Android总结之视图View总结&自定义View_第2张图片

3.1.res/values下添加attr.xml用于TimerChooser自定义属性
<resources>
    <declare-styleable name="TimerChooser">
        <attr name="hour" format="integer"/>
        <attr name="minute" format="integer"/>
        <attr name="textColor" format="color"/>
        <attr name="highlightTextColor" format="color"/>
        <attr name="highlightLineColor" format="color"/>
    declare-styleable>
resources>

添加完attr.xml并做完3.2步后在layout文件中加入如下代码即可使用以下自定义属性

xmlns:app="http://schemas.android.com/apk/res-auto"
property remark
app:hour 小时的值
app:minute 分钟的值
app:textColor 未被选中字体颜色
app:highlightTextColor 被选中字体颜色
app:highlightLineColor 被选中线颜色
3.2.定义子类继承View
3.2.1.定义构造方法,参考android.view.View.java中构造方法

主要看第4个构造方法,将我们在xml中自定义的属性值设置好,如app:textColor设置未被选中字体颜色,可通过mTextColor = a.getColor(attr, Color.GRAY);获取xml布局文件中TimerChooser控件的app:textColor属性值

public TimerChooser(Context context) {
    this(context,null);
}

public TimerChooser(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public TimerChooser(Context context, AttributeSet attrs, int defStyleAttr) {
    this(context, attrs, defStyleAttr, 0);
}

public TimerChooser(Context context, AttributeSet attrs, int defStyleAttr,
				 int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    // in a condition when a.getIndexCount() is equals to zero (TypedArray a)
    mHour = NOW_TIME.get(Calendar.HOUR_OF_DAY);
    mMinute = NOW_TIME.get(Calendar.MINUTE);
    mBlock = NO_BLOCK;
    mTextColor = Color.GRAY;
    mHighlightTextColor = Color.RED;
    mHighlightLineColor = Color.RED;

    final TypedArray a = context.obtainStyledAttributes(
            attrs, R.styleable.TimerChooser, defStyleAttr, defStyleRes);
    final int N = a.getIndexCount();
    for (int i = 0; i < N; i++) {
        int attr = a.getIndex(i);
        switch (attr) {
            case R.styleable.TimerChooser_hour:
                mHour = a.getInt(attr, NOW_TIME.get(Calendar.HOUR_OF_DAY));
                break;
            case R.styleable.TimerChooser_minute:
                mMinute = a.getInt(attr, NOW_TIME.get(Calendar.MINUTE));
                break;
            case R.styleable.TimerChooser_textColor:
                mTextColor = a.getColor(attr, Color.GRAY);
                break;
            case R.styleable.TimerChooser_highlightTextColor:
                mHighlightTextColor = a.getColor(attr, Color.RED);
                break;
            case R.styleable.TimerChooser_highlightLineColor:
                mHighlightLineColor = a.getColor(attr, Color.RED);
                break;
            default:
                break;
        }
    }
    a.recycle();
}
3.2.2.重写onMeasure方法,参考android.view.View.java中onMeasure方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    setMeasuredDimension(widthMeasureSpec, getDefaultHeight(heightMeasureSpec));
}
3.2.3.重写onDraw方法,参考android.view.View.java中onDraw方法
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    doOnDraw(canvas);
}
3.2.4.设置监听器定义TimerChooser值(小时和分钟)改变的回调方法
/**
* Interface definition for a callback to be invoked 
* when TimerChooser value changed.
*/
public interface OnTimerValueListener {
    /**
     * When Timer Value changed, notify changed value.
     *
     * @param v The view the key has been dispatched to.
     * @param hour The hour value users have selected.
     * @param minute The minute value users have selected.
     */
    void onTimerValueChanged(View v, int hour, int minute);
}
3.2.5.重写onTouchEvent方法
  • 手指按下(MotionEvent.ACTION_DOWN):记录下手指操作的当前区域,小时Block或者分钟Block
  • 手指滑动(MotionEvent.ACTION_MOVE):不作处理
  • 手指松开(MotionEvent.ACTION_UP):计算出滑动后的小时和分钟数值,并使用mOnTimerValueListener通知小时分钟值的变化
@Override
public boolean onTouchEvent(MotionEvent event) {
    float eventX = event.getX();
    float eventY = event.getY();
    Log.d(TAG, eventX+"/"+eventY);
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.d(TAG,"ACTION_DOWN");
            if(eventX > mTimerDrawable.mStartX&&
                    eventX < mTimerDrawable.mStartX + mTimerDrawable.mViewHalfWidth){
                mBlock = HOUR_BLOCK;
                Log.d(TAG,"HOUR_BLOCK");
            }else if(eventX > mTimerDrawable.mCenterX&&
                    eventX < mTimerDrawable.mCenterX + mTimerDrawable.mViewHalfWidth){
                mBlock = MINUTE_BLOCK;
                Log.d(TAG,"MINUTE_BLOCK");
            }else{
                mBlock = NO_BLOCK;
                Log.d(TAG,"NO_BLOCK");
            }
            break;
        case MotionEvent.ACTION_MOVE:
            Log.d(TAG,"ACTION_MOVE");
            break;
        case MotionEvent.ACTION_UP:
            Log.d(TAG,"ACTION_UP");
            if(eventY < mTimerDrawable.mStartY){
                if(mBlock == HOUR_BLOCK){
                    mHour = (mHour+24+1) %24;
                }else if(mBlock == MINUTE_BLOCK){
                    mMinute = (mMinute+60+1) %60;
                }else{
                }

            }else if(eventY > mTimerDrawable.mStartY + mTimerDrawable.mViewHeight){
                if(mBlock == HOUR_BLOCK){
                    mHour = (mHour+24) %24 == 0?23:(mHour+24) %24-1;
                }else if(mBlock == MINUTE_BLOCK){
                    mMinute = (mMinute+60) %60 == 0?59:(mMinute+60) %60-1;
                }else{
                }
            }
            // call the listener method
            if(mOnTimerValueListener != null){
                mOnTimerValueListener.onTimerValueChanged(this, mHour, mMinute);
            }
            invalidate();
            break;
        default:
            break;
    }
    return true;
}

3.3.layout布局文件下添加TimerChooser视图
<org.ibu.ialarmclock.view.TimerChooser
        android:id="@+id/timer_chooser"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:textColor="#000000"
   />
3.4.在Activity中使用TimerChooser视图并使用监听器打印小时分钟值的日志
TimerChooser timerChooser = findViewById(R.id.timer_chooser);
timerChooser.setTimerValueListener(new TimerChooser.OnTimerValueListener() {
    @Override
    public void onTimerValueChanged(View v, int hour, int minute) {
        Log.d(TAG, hour+"/"+minute);
    }
});

4.自定义ViewGroup

详见官网,这里不赘述了。

你可能感兴趣的:(Android)