近来忙着银联支付接口对接,博客也没有更新。在前几篇Android自定义View基础篇当中有几处地方明显不足。例如:view中使用handler 就不合理,view中自带了post方法。在view小结篇当中主要讲解自定义过程中的一些疑问及踩过的坑。
1、自定义View中的wrap_content
从ViewRoot的performTraversals开始,经过measure,layout,draw 三个流程。draw流程结束以后就可以在屏幕上看到view了。
经常我们会遇到自定义View在xml中设置wrap_content属性效果跟match_parent一样的。这个时候我们就需要在代码中处理了:
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(200, 200);
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(200, heightSpecSize);
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSpecSize, 200);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
一般的处理方式是固定宽高,MeasureSpec.AT_MOST模式对应的xml布局中的wrap_content
2、自定义View中的padding
如果你继承View,一般情况下在onDraw()方法处理;如果你继承viewGroup,那在onMeasure和onLayout里面也要考虑。
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int paddingTop = getPaddingTop();
final int paddingBottom = getPaddingBottom();
- 1
- 2
- 3
- 4
获取当前控件的padding值。
3、线程、动画
view提供了post方法处理线程,view的动画或者线程需要停止,可以考虑在onDetachedFromWindow里面来做。
4、在activity获取View的宽高
measure的过程和activity的生命周期没有任何关系。你无法确定在哪个生命周期执行完毕以后 view的measure过程一定完成。你可以使用如下几种方法来获取。
方法一:
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
int width = custom.getMeasuredWidth();
int height = custom.getMeasuredHeight();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
方法二:
@Override
protected void onStart() {
super.onStart();
custom.post(new Runnable() {
@Override
public void run() {
int width = custom.getMeasuredWidth();
int height = custom.getMeasuredHeight();
}
});
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
方法三:
@Override
protected void onStart() {
super.onStart();
ViewTreeObserver observer = custom.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onGlobalLayout() {
int width = custom.getMeasuredWidth();
int height = custom.getMeasuredHeight();
custom.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
5、简单案例
继承View的案例:
public class CircleView extends View {
final Paint paint = new Paint();
public CircleView(Context context) {
this(context, null);
}
public CircleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(200, 200);
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(200, heightSpecSize);
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSpecSize, 200);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//处理padding情况
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int paddingTop = getPaddingTop();
final int paddingBottom = getPaddingBottom();
int width = getWidth() - paddingLeft - paddingRight;
int height = getHeight() - paddingTop - paddingBottom;
int radius = (int) (Math.min(width, height) / 2 * (0.7f));
canvas.drawCircle(getWidth() / 2 + paddingLeft, getHeight() / 2 + paddingTop, radius, paint);
}
@Override
public boolean postDelayed(Runnable action, long delayMillis) {
return super.postDelayed(action, delayMillis);
}
/**
* 从窗体上分离
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
继承ViewGroup:
public class CustomHorizontalLayout extends ViewGroup {
//设置默认的控件最小是多少 这里不提供自定义属性了 写死在代码里 你们可以自行拓展
final int minHeight = 0;
final int minWidth = 0;
public CustomHorizontalLayout(Context context) {
this(context, null);
}
public CustomHorizontalLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomHorizontalLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int measureWidth = 0;
int measureHeight = 0;
final int childCount = getChildCount();
measureChildren(widthMeasureSpec, heightMeasureSpec);
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int paddingTop = getPaddingTop();
final int paddingBottom = getPaddingBottom();
//没有子控件
if (childCount == 0) {
if (widthSpecMode == MeasureSpec.AT_MOST || heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(minWidth, minHeight);
} else {
//否则根据我们的layout属性来
setMeasuredDimension(getLayoutParams().width, getLayoutParams().height);
}
} else if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
for (int i = 0; i < childCount; i++) {
final View view = getChildAt(i);
measureWidth += view.getMeasuredWidth();
measureHeight = measureHeight >= view.getMeasuredHeight() ? measureHeight : view.getMeasuredHeight();
}
setMeasuredDimension(paddingLeft + measureWidth + paddingRight, paddingTop + measureHeight + paddingBottom);
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
for (int i = 0; i < childCount; i++) {
final View view = getChildAt(i);
measureHeight = measureHeight >= view.getMeasuredHeight() ? measureHeight :view.getMeasuredHeight();
}
setMeasuredDimension(paddingLeft + paddingRight + widthSpecSize, paddingTop + paddingBottom + measureHeight);
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
for (int i = 0; i < childCount; i++) {
final View view = getChildAt(i);
measureWidth += view.getMeasuredWidth();
}
setMeasuredDimension(paddingLeft + paddingRight + measureWidth, paddingTop + paddingBottom + heightSpecSize);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int paddingTop = getPaddingTop();
final int paddingBottom = getPaddingBottom();
//左边初始位置为0
int childLeft = 0 + paddingLeft;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View childView = getChildAt(i);
if (childView.getVisibility() == View.GONE) {
continue;
}
final int childWidth = childView.getMeasuredWidth();
childView.layout(childLeft, 0 + paddingTop, childLeft + childWidth, paddingTop + childView.getMeasuredHeight());
childLeft += childWidth;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
如有什么疑问,请给我留言。
转自:https://blog.csdn.net/u012551350/article/details/51014946
近来忙着银联支付接口对接,博客也没有更新。在前几篇Android自定义View基础篇当中有几处地方明显不足。例如:view中使用handler 就不合理,view中自带了post方法。在view小结篇当中主要讲解自定义过程中的一些疑问及踩过的坑。
1、自定义View中的wrap_content
从ViewRoot的performTraversals开始,经过measure,layout,draw 三个流程。draw流程结束以后就可以在屏幕上看到view了。
经常我们会遇到自定义View在xml中设置wrap_content属性效果跟match_parent一样的。这个时候我们就需要在代码中处理了:
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(200, 200);
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(200, heightSpecSize);
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSpecSize, 200);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
一般的处理方式是固定宽高,MeasureSpec.AT_MOST模式对应的xml布局中的wrap_content
2、自定义View中的padding
如果你继承View,一般情况下在onDraw()方法处理;如果你继承viewGroup,那在onMeasure和onLayout里面也要考虑。
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int paddingTop = getPaddingTop();
final int paddingBottom = getPaddingBottom();
- 1
- 2
- 3
- 4
获取当前控件的padding值。
3、线程、动画
view提供了post方法处理线程,view的动画或者线程需要停止,可以考虑在onDetachedFromWindow里面来做。
4、在activity获取View的宽高
measure的过程和activity的生命周期没有任何关系。你无法确定在哪个生命周期执行完毕以后 view的measure过程一定完成。你可以使用如下几种方法来获取。
方法一:
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
int width = custom.getMeasuredWidth();
int height = custom.getMeasuredHeight();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
方法二:
@Override
protected void onStart() {
super.onStart();
custom.post(new Runnable() {
@Override
public void run() {
int width = custom.getMeasuredWidth();
int height = custom.getMeasuredHeight();
}
});
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
方法三:
@Override
protected void onStart() {
super.onStart();
ViewTreeObserver observer = custom.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onGlobalLayout() {
int width = custom.getMeasuredWidth();
int height = custom.getMeasuredHeight();
custom.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
5、简单案例
继承View的案例:
public class CircleView extends View {
final Paint paint = new Paint();
public CircleView(Context context) {
this(context, null);
}
public CircleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(200, 200);
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(200, heightSpecSize);
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSpecSize, 200);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//处理padding情况
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int paddingTop = getPaddingTop();
final int paddingBottom = getPaddingBottom();
int width = getWidth() - paddingLeft - paddingRight;
int height = getHeight() - paddingTop - paddingBottom;
int radius = (int) (Math.min(width, height) / 2 * (0.7f));
canvas.drawCircle(getWidth() / 2 + paddingLeft, getHeight() / 2 + paddingTop, radius, paint);
}
@Override
public boolean postDelayed(Runnable action, long delayMillis) {
return super.postDelayed(action, delayMillis);
}
/**
* 从窗体上分离
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
继承ViewGroup:
public class CustomHorizontalLayout extends ViewGroup {
//设置默认的控件最小是多少 这里不提供自定义属性了 写死在代码里 你们可以自行拓展
final int minHeight = 0;
final int minWidth = 0;
public CustomHorizontalLayout(Context context) {
this(context, null);
}
public CustomHorizontalLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomHorizontalLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int measureWidth = 0;
int measureHeight = 0;
final int childCount = getChildCount();
measureChildren(widthMeasureSpec, heightMeasureSpec);
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int paddingTop = getPaddingTop();
final int paddingBottom = getPaddingBottom();
//没有子控件
if (childCount == 0) {
if (widthSpecMode == MeasureSpec.AT_MOST || heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(minWidth, minHeight);
} else {
//否则根据我们的layout属性来
setMeasuredDimension(getLayoutParams().width, getLayoutParams().height);
}
} else if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
for (int i = 0; i < childCount; i++) {
final View view = getChildAt(i);
measureWidth += view.getMeasuredWidth();
measureHeight = measureHeight >= view.getMeasuredHeight() ? measureHeight : view.getMeasuredHeight();
}
setMeasuredDimension(paddingLeft + measureWidth + paddingRight, paddingTop + measureHeight + paddingBottom);
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
for (int i = 0; i < childCount; i++) {
final View view = getChildAt(i);
measureHeight = measureHeight >= view.getMeasuredHeight() ? measureHeight :view.getMeasuredHeight();
}
setMeasuredDimension(paddingLeft + paddingRight + widthSpecSize, paddingTop + paddingBottom + measureHeight);
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
for (int i = 0; i < childCount; i++) {
final View view = getChildAt(i);
measureWidth += view.getMeasuredWidth();
}
setMeasuredDimension(paddingLeft + paddingRight + measureWidth, paddingTop + paddingBottom + heightSpecSize);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int paddingTop = getPaddingTop();
final int paddingBottom = getPaddingBottom();
//左边初始位置为0
int childLeft = 0 + paddingLeft;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View childView = getChildAt(i);
if (childView.getVisibility() == View.GONE) {
continue;
}
final int childWidth = childView.getMeasuredWidth();
childView.layout(childLeft, 0 + paddingTop, childLeft + childWidth, paddingTop + childView.getMeasuredHeight());
childLeft += childWidth;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
如有什么疑问,请给我留言。