【5年Android从零复盘系列之六】Android自定义View(1):基础
16lz
2021-01-26
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"> <attr name="mdb_bg" format="color|reference" /> <attr name="mdb_txt_color" format="color|reference" /> <attr name="mdb_txt" format="string" /> <attr name="mdb_auto_anim" format="boolean" /> <attr name="mdb_anim_pivotX" format="fraction" /> <attr name="mdb_auto_anim_delay" format="integer" /> <attr name="mdb_auto_anim_alpha" format="float" /> <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> <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=big int 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中使用控件,【注意变量组设置的数据&单位】
<LinearLayout android: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.MDButton app: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.MDButton app: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.MDButton app: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(1):组合式
3.2 继承覆写
简而言之,即 如继承Button,修改默认background、state_press状态时按钮elevation值、取消默认最小高度56dp等。
也是最常用的、直接扩展/修改原生View功能
Android自定义View(2):继承改写
3.3 自绘式
强烈建议:熟悉View的绘制、Android事件传递、手势处理再入手自绘式。
方式:直接继承View ,重写绘制流程三步骤
- measure() 测量
- layout() 布局计算摆放坐标
- draw() 绘制
Android自定义View(3):自绘式
更多相关文章
- 调用Android原生裁剪方式裁剪图片并保存
- Android调用系统相册和相机选择图片并显示在imageview中
- 关于android双卡手机sim卡信息采集适配的心得
- Android相机、相册获取图片,解决相机拍照图片被压缩模糊的情况
- BroadcastReceiver与Notification的综合应用之自定义Action的调
- Android(安卓)Studio精彩案例(三)《模仿微信ViewPage+Fragment实
- Android上hook AMS和PMS
- Android获取数据时 浮点型整数位数值(超8位)过大导致科学计数法
- android相机如何只显示处理后的图像以及这里onPreviewFrame不被