【5年Android从零复盘系列之六】Android自定义View(1):基础详解(图文)
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 ,重写绘制流程三步骤
- measure() 测量
- layout() 布局计算摆放坐标
- draw() 绘制
Android自定义View(4):自绘式
4.View的生命周期
View的生命周期,关联Activity联动时的函数调用顺序
- 【View】构造方法
- 【View】onFinishInflate()
- 【Activity】 onCreate()
- 【Activity】onStart()
- 【Activity】onResume()
- 【View】onAttachedToWindow()
- 【View】onMeasure() (可能调用n次)
- 【View】onSizeChanged() (可能调用n次)
- 【View】onLayout() (可能调用n次)
- 【View】onDraw() (可能调用n次)
- 【View】onWindowFocusChanged() (调用Activity.onPause()前,被调用,hasWindowFocus==false)
- 【Activity】onPause()
- 【Activity】onStop()
- 【Activity】onDestroy()
- 【View】onDetachedFromWindow
【5年Android从零复盘系列之六】Android自定义View(1):基础详解(图文)相关推荐
- 【5年Android从零复盘系列之十七】Android自定义View(12):手势绘制及GestureOverlayView事件详解(图文)
[5年Android从零复盘系列之十七]Android自定义View(12):手势绘制及GestureOverlayView事件浅析 1.基础 掌握View体系事件分发与处理,参考Android自定义 ...
- 【5年Android从零复盘系列之二十】Android自定义View(15):Matrix详解(图文)【转载】
[转载]本文转载自麻花儿wt 的文章<android matrix 最全方法详解与进阶(完整篇)> [5年Android从零复盘系列之二十]Android自定义View(15):Matri ...
- Android自定义View进阶-MotionEvent详解
欢迎Follow我的GitHub, 关注我的CSDN. 其余参考Android目录 我们微信公众号:杨守乐 推荐文章: 如果你喜欢上了一个程序员小伙,献给所有的程序员女友 学习资料(干货汇集)不断更新 ...
- android butterknife 自定义view,ButterKnife用法详解.md
# ButterKnife用法详解 ### 如何成为T型人才,垂直在一个行业中,必须要有一整套[知识体系](https://github.com/WeiSmart/Android-Advanced-C ...
- Webflux系列之反应式编程核心基础详解
常用官网学习地址 反应编程Reatvie programmming : https://projectreactor.io/docs/core/release/reference/ webflux ...
- 【Android从零单排系列十一】《Android视图控件——日历、日期、时间选择控件》
目录 一.日历.日期.时间组件基本介绍 二.几种常见的控件类型 1.CalendarView –日历控件 2. DatePicker –日期选择控件 3.TimePicker –时间选择控件 4.Ch ...
- Android音视频学习系列(九) — Android端实现rtmp推流
系列文章 Android音视频学习系列(一) - JNI从入门到精通 Android音视频学习系列(二) - 交叉编译动态库.静态库的入门 Android音视频学习系列(三) - Shell脚本入门 ...
- Android自定义view之基础知识
Android自定义view之基础知识 虽然Android已经自带了很多实用的view和layout,加以调教能实现很美观的界面,但是有一些情况下,需要实现特殊的界面效果,比如我们比较熟悉的各种播放器 ...
- Android 进阶——Framework 核心之Android Storage Access Framework(SAF)存储访问框架机制详解(一)
文章大纲 引言 一.Android Storage Access Framework 二.Storage Access Framework 的主要角色成员 1.Document Provider 文件 ...
最新文章
- 微生物组:3分和30分文章差距在哪里?
- 扩增子文献笔记2拟南芥根微生物组的结构和组成
- 送你16个matplotlib绘图实用小技巧(附代码)
- 解决无扬声器(无喇叭)的HDMI接口显示屏声音问题
- mysql 5.0 to mysql 5.1的BTREE索引问题
- Linux日志系统-01:什么是rsyslog?
- Scalaz(27)- Inference Unapply :类型的推导和匹配
- (jQuery,Highcharts)前端图表系列之一 --Highcharts (转)
- Palo Alto Networks全球化安全堡垒理念 提升企业防御能力
- python qt 按钮_PyQt(Python+Qt)学习随笔:toolButton的popupMode属性
- cximage 控制台 程序 显示图片_VisualStudio创建程序(Create a program)
- jQueryMobile新版中导航栏按钮消失的解决方法
- 期末数据结构复习的一点笔记
- matlab intersect
- vbScript: 编号成生不夠位數前面加零
- async spring 默认线程池_Spring定时任务高级使用篇
- 余贞侠C语言程序设计课后参考答案
- vs2015安装+下载详细教程
- 再理解:LNode、*LinkList
- 双摄像头系列原理深度剖析【转载】