当前位置:   article > 正文

自定义view学习_自定义view三部曲

自定义view三部曲

一,自定义view理论:

自定义view三部曲:onMeasure() onLayout()   onDraw()

自定义view可以粗略的分为两类,1,自定义View,一般继承自View,主要实现onMeasure()与onDraw()方法,2,继承ViewGroup,主要实现onMeasure()与onLayout()方法

自定义View的生命周期:构造函数(view的初始化)onMeasure()(测量view的大小)  onChangeSize()(确定view的大小)onLayout()(确定子view的布局,包含子view的使用)onDraw()(实际绘制View)

什么时MeasureSpec?

MeasureSpec 是View的内部类,基本都是二进制运算,由于int是32位的,用高两位表示mode,低30位表示size,MODE_SHIFT = 30的作用是位移,是父容器给你的度量之后的大小的确定

分为三种情况:1,UNSPECIFIED:不对view大小做限制,基本在系统中使用

2,EXACTLY:父容器已经得到自己view的大小

AT_MOST:父容器指定一个大小,孩子不可超过这个值,如:matchParent,最大不能超过父容器

getMeasureWidth()是在measure()过程结束后就可以获取对应的至,是通过setMeasuredDimension()来进行设置的,

getWidth()在layout()过程结束之后才能获取到,是通过视图右边的坐标减去左边的坐标计算出来的,

二自定义View实战---流式布局实现

  1. package com.example.viewdemo.view;
  2. import android.content.Context;
  3. import android.util.AttributeSet;
  4. import android.util.TypedValue;
  5. import android.view.View;
  6. import android.view.ViewGroup;
  7. import java.util.ArrayList;
  8. import java.util.List;
  9. public class FlowLayout extends ViewGroup {
  10. private static final String TAG = "FlowLayout";
  11. private int mHorSpacing = dp2px(16);
  12. private int mVerSpacing = dp2px(8);
  13. //用来记录所用行的view与每一行的行高,用于layout布局使用
  14. private List<List<View>> allLineViews ;
  15. List<Integer> lineHeights ;
  16. public FlowLayout(Context context) {
  17. super(context);
  18. }
  19. //反射
  20. public FlowLayout(Context context, AttributeSet attrs) {
  21. super(context, attrs);
  22. }
  23. //主题style
  24. public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
  25. super(context, attrs, defStyleAttr);
  26. }
  27. /**
  28. * 初始化总记录,
  29. */
  30. private void initMeasureParams(){
  31. lineHeights = new ArrayList<>();
  32. allLineViews = new ArrayList<>();
  33. }
  34. //度量
  35. @Override
  36. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  37. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  38. /**
  39. * 可能会多次调用,在此初始化
  40. */
  41. initMeasureParams();
  42. //度量孩子大小
  43. int childCunt = getChildCount();
  44. // 父布局的padding
  45. int paddingLeft = getPaddingLeft();
  46. int paddingRight = getPaddingRight();
  47. int paddingTop = getPaddingTop();
  48. int paddingBottom = getPaddingBottom();
  49. //用来保存一行中所有的子View
  50. List<View> lineViews = new ArrayList<>();
  51. //记录这行已经使用多宽的size;
  52. int lineWidthUsed = 0;
  53. //一行的高度
  54. int lineHeigth = 0;
  55. //这是viewGroup解析的父控件给的宽高
  56. int selfWidth = MeasureSpec.getSize(widthMeasureSpec);
  57. int selfHeigth = MeasureSpec.getSize(heightMeasureSpec);
  58. //measure的过程中,子view要求的父ViewGroup 的宽高即,子view累计的宽高,本控件需要的宽高
  59. int parentNeededWidth = 0;
  60. int parentNeededHeight = 0;
  61. for (int i=0;i<childCunt;i++){
  62. View childView = getChildAt(i);
  63. //获取子控件的布局参数,layoutParams为布局参数
  64. LayoutParams childLp = childView.getLayoutParams();
  65. //将布局参数转变为具体的size大小 传参分别是 父布局widthMeasureSpec 父布局padding,及子布局宽高
  66. int childWidthMusSpc = getChildMeasureSpec(widthMeasureSpec,paddingLeft+paddingRight,childLp.width);
  67. int childHeightMusSpc = getChildMeasureSpec(widthMeasureSpec,paddingTop+paddingBottom,childLp.height);
  68. //给子view设置度量
  69. childView.measure(childWidthMusSpc,childHeightMusSpc);
  70. //获取子布局的宽高
  71. int childMeasureWidth = childView.getMeasuredWidth();
  72. int childMeasureHeight = childView.getMeasuredHeight();
  73. /**
  74. * 通过狂赌来判断是否换行,通过换行后每行的行高来获取整个view Group的行高
  75. * 因为一旦换行说明这一行的高度就确定了
  76. */
  77. if (childMeasureWidth+lineWidthUsed+mHorSpacing>selfWidth){
  78. //记录每一行的view与行高,用于layout布局
  79. allLineViews.add(lineViews);
  80. lineHeights.add(lineHeigth);
  81. //总行高就等于之前行高+本次子行高+行间距
  82. parentNeededHeight = parentNeededWidth+lineHeigth+mVerSpacing;
  83. //总行宽就等于本次之前行宽与本次行宽+子view的列间距对比最大值
  84. parentNeededWidth = Math.max(parentNeededWidth,lineWidthUsed+mHorSpacing);
  85. //换行后清空行记录的view 及本行的宽高,进行记录下一行的宽高
  86. lineViews = new ArrayList<>();
  87. lineWidthUsed = 0;
  88. lineHeigth = 0;
  89. }
  90. //view 是分行的layout,所以要记录每一行的view,这样可以方便layout布局
  91. lineViews.add(childView);
  92. //记录每一行的宽和高,每一行都会有自己的宽高
  93. lineWidthUsed = lineWidthUsed+childMeasureWidth+mHorSpacing;
  94. //因为子view的高度不确定,所以行高度自己的高度与子view的高度取最大值
  95. lineHeigth = Math.max(lineHeigth,childMeasureHeight);
  96. }
  97. /**
  98. * 因为不确定布局文件给到的宽高方式(例:)
  99. * 要根据不同的情况,需要度量自己的大小
  100. */
  101. int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  102. int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  103. int realWidth = (widthMode==MeasureSpec.EXACTLY)?selfWidth:parentNeededWidth;
  104. int realHeigth = (heightMode==MeasureSpec.EXACTLY)?selfHeigth:parentNeededHeight;
  105. //度量自己的宽高
  106. setMeasuredDimension(realWidth,realHeigth);
  107. }
  108. //布局
  109. @Override
  110. protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
  111. int lineCount = allLineViews.size();
  112. int curL = getPaddingLeft();
  113. int curT = getPaddingTop();
  114. for (int j=0;j<lineCount;j++){
  115. int lineHeight = lineHeights.get(i);
  116. List<View> lineViews = allLineViews.get(j);
  117. for (int k=0;k<lineViews.size();k++){
  118. View view = lineViews.get(i);
  119. int left = curL;
  120. int top = curT;
  121. /**
  122. * 因为getWidth()需要执行完onLayout()才会有值
  123. * 所以不能用下面的等式
  124. */
  125. // int right = left+view.getWidth();
  126. // int bottom = top+view.getHeight();
  127. /**
  128. * 正确的方式
  129. */
  130. int right = left+view.getMeasuredWidth();
  131. int bottom = top+view.getMeasuredHeight();
  132. view.layout(left,top,right,bottom);
  133. // 上面代码实现第一个子view的布局,本行后续布局需要重置left
  134. curL = right+mHorSpacing;
  135. }
  136. //单行布局完成后需要将left重置到左边
  137. curL = getPaddingLeft();
  138. //top的长度需要重新赋值 原本距上+行高+行间距
  139. curT = curT+lineHeight+mVerSpacing;
  140. }
  141. }
  142. public int dp2px(int pxValue) {
  143. return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, pxValue, getResources().getDisplayMetrics());
  144. }
  145. }

源码下载地址:https://download.csdn.net/download/feng_zhongsha/16636492

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/759888
推荐阅读
相关标签
  

闽ICP备14008679号