1.基础一:坐标计算

1.1 Android窗口坐标系计算以屏幕左上角为原点,

向右为X轴正向,向下为Y轴正向

1.2 View坐标系

【注意获取的坐标是像素值,不是dp值】
【注意获取的坐标是像素值,不是dp值】
【注意获取的坐标是像素值,不是dp值】

//获取View内部相对的坐标值(距离)
getX()、getY()
//获取View相对父View的相对坐标值(距离)
getLeft()、getTop()、getRight()、getBottom()
//获取的是屏幕中的实际坐标值(距离)
getRawX()、getRawY()

图中activity指全屏窗口,严格的讲应该是屏幕

1.3 实际开发使用场景

1.获取View的宽高【应在View绘制完成后调用

width = getRight() - getLeft();
height = getBottom() - getTop();

2.获取View在父view中的左上角坐标【应在View绘制完成后调用

Point point = new Point();
point.set(ivState.getLeft() ,ivState.getTop());

3.获取View在父view中心点坐标【应在View绘制完成后调用

Point point = new Point();
point.set(ivState.getRight() - ivState.getLeft() ,ivState.getBottom() - ivState.getTop());

2. 自定义属性

2.1 构造函数&初始化属性

public class MDButton extends Button {//java动态创建view时调用public MDButton(Context context) {super(context);initInnerView(context);}//xml布局初始化时调用public MDButton(Context context, AttributeSet attrs) {super(context, attrs);
//        initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用initAttrs(context, attrs);}//有默认style时,在MDButton(Context context, AttributeSet attrs)中调用MDButton(context,attrs,defStyleAttr);public MDButton(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);
//        initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用initAttrs(context, attrs);}//只有在API版本>21时才会用到//有默认style时,在MDButton(Context context, AttributeSet attrs)中调用MDButton(context,attrs,defStyleAttr);@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)public MDButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);
//        initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用initAttrs(context, attrs);}//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用private void initInnerView(Context context) {//...}private void initAttrs(Context context, AttributeSet attrs) {//...}
}

2.2 自定义属性

1.在module中的/res/values/attrs.xml编写属性&类型;

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="MDButton"><!--  混合类型:颜色int值+引用类型  属性定义时可以指定多种类型值--><attr name="mdb_bg" format="color|reference" /><attr name="mdb_txt_color" format="color|reference" /><!--  String --><attr name="mdb_txt" format="string" /><!--  boolean --><attr name="mdb_auto_anim" format="boolean" /><!--  百分比类型--><attr name="mdb_anim_pivotX" format="fraction" /><!--  int值  --><attr name="mdb_auto_anim_delay" format="integer" /><!--  浮点值 --><attr name="mdb_auto_anim_alpha" format="float" /><!--  dp 尺寸值--><attr name="mdb_min_width" format="dimension" /><!--    枚举类型    --><attr name="mdb_size"><enum name="small" value="0" /><enum name="normal" value="1" /><enum name="big" value="2" /></attr><!--    flag:位或运算    --><attr name="mdb_radius_corner"><flag name="empty" value="0x00" /><flag name="top" value="0x01" /><flag name="bottom" value="0x02" /><flag name="left" value="0x04" /><flag name="right" value="0x08" /></attr></declare-styleable>
</resources>

2.自定义View类中获取属性值,并使用

public class MDButton extends Button {//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用private void initInnerView(Context context) {//...}private void initAttrs(Context context, AttributeSet attrs) {//1.获取属性数组TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MDButton);//2.获取属性值Drawable bgDrawable = typedArray.getDrawable(R.styleable.MDButton_mdb_bg);int txtColor = typedArray.getInteger(R.styleable.MDButton_mdb_txt_color,Color.parseColor("#808080"));String txt = typedArray.getString(R.styleable.MDButton_mdb_txt);boolean isAutoAnim = typedArray.getBoolean(R.styleable.MDButton_mdb_auto_anim, false);float fraction = typedArray.getFraction(R.styleable.MDButton_mdb_anim_pivotX, 1, 1, 1.0f);float alpha = typedArray.getFloat(R.styleable.MDButton_mdb_auto_anim_alpha , 1.0f);float minWidth = typedArray.getDimension(R.styleable.MDButton_mdb_min_width, 32.0f);int sizeType = typedArray.getInt(R.styleable.MDButton_mdb_size, 1);//0=small 1=normal 2=bigint radiusCorner = typedArray.getInt(R.styleable.MDButton_mdb_radius_corner ,0);int delay = typedArray.getInt(R.styleable.MDButton_mdb_auto_anim_delay ,0);Log.e("bgDrawable",""+bgDrawable);Log.e("txtColor",""+txtColor);Log.e("txt",""+txt);Log.e("isAutoAnim",""+isAutoAnim);Log.e("fraction",""+fraction);Log.e("alpha",""+alpha);Log.e("minWidth",""+minWidth);Log.e("sizeType",""+sizeType);Log.e("radiusCorner",""+radiusCorner);Log.e("delay",""+delay);Log.e("==============","=========================================");//3.属性值 设置到 对应属性setText(txt);//tv.setDelay(delay);//...//4.释放typedArray.recycle();}//java动态创建view时调用public MDButton(Context context) {super(context);initInnerView(context);}//xml布局初始化时调用public MDButton(Context context, AttributeSet attrs) {super(context, attrs);
//        initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用initAttrs(context, attrs);}//有默认style时,在MDButton(Context context, AttributeSet attrs)中调用MDButton(context,attrs,defStyleAttr);public MDButton(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);
//        initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用initAttrs(context, attrs);}//只有在API版本>21时才会用到//有默认style时,在MDButton(Context context, AttributeSet attrs)中调用@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)public MDButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);
//        initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用initAttrs(context, attrs);}
}

3.在布局文件.xml中使用控件,【注意变量组设置的数据&单位】

 <LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintLeft_toLeftOf="parent"android:orientation="vertical"><com.cupster.base_super_resource.MDButtonapp:mdb_anim_pivotX="80%"app:mdb_auto_anim="true"app:mdb_auto_anim_alpha="1.0"app:mdb_auto_anim_delay="100"app:mdb_bg="@drawable/shape_btn_gray_radius5"app:mdb_min_width="60dp"app:mdb_radius_corner="right"app:mdb_size="big"app:mdb_txt="btn1"app:mdb_txt_color="#ff00ff"android:layout_width="120dp"android:layout_height="60dp"/><com.cupster.base_super_resource.MDButtonapp:mdb_anim_pivotX="70%"app:mdb_auto_anim="false"app:mdb_auto_anim_alpha="0.4"app:mdb_auto_anim_delay="100"app:mdb_bg="@drawable/shape_btn_gray_radius5"app:mdb_min_width="60px"app:mdb_radius_corner="bottom|left|top|right"app:mdb_size="small"app:mdb_txt="btn1"app:mdb_txt_color="#ff00ff"android:layout_width="120dp"android:layout_height="60dp"/><com.cupster.base_super_resource.MDButtonapp:mdb_anim_pivotX="100%"app:mdb_auto_anim_alpha="0.9"app:mdb_auto_anim_delay="100"app:mdb_bg="@drawable/shape_btn_gray_radius5"app:mdb_min_width="90dp"app:mdb_radius_corner="empty"app:mdb_size="normal"app:mdb_txt="btn1"app:mdb_txt_color="#ff00ff"android:layout_width="120dp"android:layout_height="60dp"/></LinearLayout>

** 附 :属性值获取正确性验证**

3.自定义View分类

3.1 组合式

顾名思义,即xml文件中根布局使用RelativeLayout(同理其他布局控件),
内部使用其他View控件,布局摆放,组合成XxxView的原始布局。
然后,Java类继承根布局标签对应的容器类,覆写构造函数,并初始化各子View的变量。
是最常用、最稳妥、不易产生过度绘制、内存泄漏等问题。

Android自定义View(2):组合式

3.2 继承覆写、衍生/扩展

简而言之,即 如继承Button,修改默认background、state_press状态时按钮elevation值、取消默认最小高度56dp等。
也是最常用的、直接扩展/修改原生View功能

Android自定义View(3):继承改写、衍生/扩展

3.3 自绘式

强烈建议:熟悉View的绘制、Android事件传递、手势处理再入手自绘式。

方式:直接继承View ,重写绘制流程三步骤

  1. measure() 测量
  2. layout() 布局计算摆放坐标
  3. draw() 绘制

Android自定义View(4):自绘式

4.View的生命周期

View的生命周期,关联Activity联动时的函数调用顺序

  1. 【View】构造方法
  2. 【View】onFinishInflate()
  3. 【Activity】 onCreate()
  4. 【Activity】onStart()
  5. 【Activity】onResume()
  6. 【View】onAttachedToWindow()
  7. 【View】onMeasure() (可能调用n次)
  8. 【View】onSizeChanged() (可能调用n次)
  9. 【View】onLayout() (可能调用n次)
  10. 【View】onDraw() (可能调用n次)
  11. 【View】onWindowFocusChanged() (调用Activity.onPause()前,被调用,hasWindowFocus==false)
  12. 【Activity】onPause()
  13. 【Activity】onStop()
  14. 【Activity】onDestroy()
  15. 【View】onDetachedFromWindow

【5年Android从零复盘系列之六】Android自定义View(1):基础详解(图文)相关推荐

  1. 【5年Android从零复盘系列之十七】Android自定义View(12):手势绘制及GestureOverlayView事件详解(图文)

    [5年Android从零复盘系列之十七]Android自定义View(12):手势绘制及GestureOverlayView事件浅析 1.基础 掌握View体系事件分发与处理,参考Android自定义 ...

  2. 【5年Android从零复盘系列之二十】Android自定义View(15):Matrix详解(图文)【转载】

    [转载]本文转载自麻花儿wt 的文章<android matrix 最全方法详解与进阶(完整篇)> [5年Android从零复盘系列之二十]Android自定义View(15):Matri ...

  3. Android自定义View进阶-MotionEvent详解

    欢迎Follow我的GitHub, 关注我的CSDN. 其余参考Android目录 我们微信公众号:杨守乐 推荐文章: 如果你喜欢上了一个程序员小伙,献给所有的程序员女友 学习资料(干货汇集)不断更新 ...

  4. android butterknife 自定义view,ButterKnife用法详解.md

    # ButterKnife用法详解 ### 如何成为T型人才,垂直在一个行业中,必须要有一整套[知识体系](https://github.com/WeiSmart/Android-Advanced-C ...

  5. Webflux系列之反应式编程核心基础详解

    常用官网学习地址 反应编程Reatvie programmming :   https://projectreactor.io/docs/core/release/reference/ webflux ...

  6. 【Android从零单排系列十一】《Android视图控件——日历、日期、时间选择控件》

    目录 一.日历.日期.时间组件基本介绍 二.几种常见的控件类型 1.CalendarView –日历控件 2. DatePicker –日期选择控件 3.TimePicker –时间选择控件 4.Ch ...

  7. Android音视频学习系列(九) — Android端实现rtmp推流

    系列文章 Android音视频学习系列(一) - JNI从入门到精通 Android音视频学习系列(二) - 交叉编译动态库.静态库的入门 Android音视频学习系列(三) - Shell脚本入门 ...

  8. Android自定义view之基础知识

    Android自定义view之基础知识 虽然Android已经自带了很多实用的view和layout,加以调教能实现很美观的界面,但是有一些情况下,需要实现特殊的界面效果,比如我们比较熟悉的各种播放器 ...

  9. Android 进阶——Framework 核心之Android Storage Access Framework(SAF)存储访问框架机制详解(一)

    文章大纲 引言 一.Android Storage Access Framework 二.Storage Access Framework 的主要角色成员 1.Document Provider 文件 ...

最新文章

  1. 微生物组:3分和30分文章差距在哪里?
  2. 扩增子文献笔记2拟南芥根微生物组的结构和组成
  3. 送你16个matplotlib绘图实用小技巧(附代码)
  4. 解决无扬声器(无喇叭)的HDMI接口显示屏声音问题
  5. mysql 5.0 to mysql 5.1的BTREE索引问题
  6. Linux日志系统-01:什么是rsyslog?
  7. Scalaz(27)- Inference Unapply :类型的推导和匹配
  8. (jQuery,Highcharts)前端图表系列之一 --Highcharts (转)
  9. Palo Alto Networks全球化安全堡垒理念 提升企业防御能力
  10. python qt 按钮_PyQt(Python+Qt)学习随笔:toolButton的popupMode属性
  11. cximage 控制台 程序 显示图片_VisualStudio创建程序(Create a program)
  12. jQueryMobile新版中导航栏按钮消失的解决方法
  13. 期末数据结构复习的一点笔记
  14. matlab intersect
  15. vbScript: 编号成生不夠位數前面加零
  16. async spring 默认线程池_Spring定时任务高级使用篇
  17. 余贞侠C语言程序设计课后参考答案
  18. vs2015安装+下载详细教程
  19. 再理解:LNode、*LinkList
  20. 双摄像头系列原理深度剖析【转载】

热门文章

  1. Ideal比较好用、常用的快捷键
  2. 2023年天猫青团销售数据:口味更个性化,但老字号品牌依然称霸
  3. 尘埃落定 -- 再见了兄弟们
  4. 【毕业设计/课程设计】基于android的安卓景点旅游助手app设计与实现(源码+文章)
  5. CCC3.0学习笔记_数字密钥分享
  6. Animation Animate Armture三个动画的使用
  7. [QT] QMap使用详解
  8. python回车符是什么_python换行符是什么?
  9. 什么是感受野 Receptive Field 感受野是什么意思
  10. SAP ABAP 根据修改内容查询CR