[关闭]
@mSolo 2015-04-10T13:44:09.000000Z 字数 5391 阅读 1905

实战 Android 自定义 View

Android Java 设计模式


基础知识

参考资料:《Expert Android》 + 《Android Programming Pushing》

View 的类层次

View 的生命周期

Layout Phase : Measurement and Layout

目的 -> 获取 View 的大小和位置。该阶段包含两个子过程:onMeasure() + onLayout()

Drawing Phase : Mechanics of onDraw

Measure 子过程剖析

在 View 类中 onMeasure() 的默认实现

  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  2. setMeasuredDimension(
  3. getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
  4. getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
  5. }
  6. public static int getDefaultSize(int size, int measureSpec) {
  7. int result = size;
  8. int specMode = MeasureSpec.getMode(measureSpec);
  9. int specSize = MeasureSpec.getSize(measureSpec);
  10. switch (specMode) {
  11. case MeasureSpec.UNSPECIFIED:
  12. result = size;
  13. break;
  14. case MeasureSpec.AT_MOST:
  15. case MeasureSpec.EXACTLY:
  16. result = specSize;
  17. break;
  18. }
  19. return result;
  20. }

另一种自定义实现

  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  2. setMeasuredDimension(
  3. getImprovedDefaultWidth(widthMeasureSpec),
  4. getImprovedDefaultHeight(heightMeasureSpec));
  5. }
  6. private int getImprovedDefaultHeight(int measureSpec) {
  7. int specMode = MeasureSpec.getMode(measureSpec);
  8. int specSize = MeasureSpec.getSize(measureSpec);
  9. switch (specMode) {
  10. case MeasureSpec.UNSPECIFIED:
  11. return hGetMaximumHeight();
  12. case MeasureSpec.EXACTLY:
  13. return specSize;
  14. case MeasureSpec.AT_MOST:
  15. return hGetMinimumHeight();
  16. }
  17. // shouldn't come here
  18. Log.e(tag,"unknown specmode");
  19. return specSize;
  20. }
  21. protected int hGetMinimumHeight() {
  22. return this.getSuggestedMinimumHeight();
  23. }

Draw 过程示例 :onDraw()

  1. @Override
  2. public void onDraw(Canvas canvas) {
  3. super.onDraw(canvas);
  4. int w = this.getWidth();
  5. int h = this.getHeight();
  6. int t = this.getTop();
  7. int l = this.getLeft();
  8. int ox = w/2;
  9. int oy = h/2;
  10. int rad = Math.min(ox,oy)/2;
  11. canvas.drawCircle(ox, oy, rad, getBrush());
  12. }

自定义属性

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:circleViewPkg="http://schemas.android.com/apk/res/com.androidbook.custom"
  3. ....
  4. <com.androidbook.custom.CircleView
  5. android:id="@+id/circle_view_id"
  6. android:layout_width="wrap_content"
  7. android:layout_height="wrap_content"
  8. circleViewPkg:strokeWidth="5"
  9. circleViewPkg:strokeColor="@android:color/holo_red_dark"
  10. />
  11. </LinearLayout>
  12. ...
  13. <resources>
  14. <declare-styleable name="CircleView">
  15. <attr name="strokeWidth" format="integer"/>
  16. <attr name="strokeColor" format="color|reference" />
  17. </declare-styleable>
  18. </resources>
  19. ...
  1. publicCircleView(Context context, AttributeSet attrs, int defStyle){
  2. super(context, attrs, defStyle);
  3. //Use the array constant to read the bag once
  4. TypedArray t = context.obtainStyledAttributes(attrs,
  5. R.styleable.CircleView,
  6. defStyle, 0);
  7. strokeColor = t.getColor(R.styleable.CircleView_strokeColor, strokeColor);
  8. strokeWidth = t.getInt(R.styleable.CircleView_strokeWidth, strokeWidth);
  9. //Recycle the typed array
  10. t.recycle();
  11. initCircleView();
  12. }

案例研究

出处:https://github.com/daimajia/NumberProgressBar

实战

出处:https://github.com/mSoloYu/StyleNumberProgressBar
以桥接(Bridge)设计模式改造 NumberProgressbar 库文件;
在第 1 步基础上,实现更多 Progressbar 的定制;

项目库包结构

最终效果

示范

attrs.xml 的改变

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3. <declare-styleable name="NumberProgressBar">
  4. <attr name="progress" format="integer"/>
  5. <attr name="progress_unreached_color" format="color"/>
  6. <attr name="progress_reached_color" format="color"/>
  7. <attr name="progress_reached_bar_size" format="dimension"/>
  8. <attr name="progress_unreached_bar_size" format="dimension"/>
  9. <attr name="progress_text_size" format="dimension"/>
  10. <attr name="progress_text_color" format="color"/>
  11. <attr name="progress_text_offset" format="dimension"/>
  12. <attr name="progress_timeline" format="string" />
  13. <attr name="progress_text" format="string" />
  14. <attr name="progress_shape" format="enum">
  15. <enum name="horizontal_default" value="0" />
  16. <enum name="vertical_default" value="1" />
  17. <enum name="horizontal_timeline" value="2" />
  18. <enum name="vertical_timeline" value="3" />
  19. <enum name="pie_default" value="4" />
  20. </attr>
  21. </declare-styleable>
  22. </resources>

View.java(AOSP)

StyleNumberProgressBar.java

TemplateTextProgressShape.java

TextHoriTimelineProgressBar.java
TextHorizontalProgressBar.java
TextVerticalProgressBar.java
TextPieProgressBar.java

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注