热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

android开发分享自定义view大杂烩

文章目录自定义控件自定义控件:第一步自定义控件:第二步自定义控件:总结绘制view视图绘制大小:MeasureSpec测量模式开始实践设置view大小如何自定义view1.demo

文章目录

        • 自定义控件
          • 自定义控件:第一步
          • 自定义控件:第二步
          • 自定义控件:总结
        • 绘制view视图
          • 绘制大小:MeasureSpec
            • 测量模式
          • 开始实践
          • 设置view大小
        • 如何自定义view
          • 1.demo
          • 2.添加wrap_content的支持
          • 3.添加padding的支持[margin是由父布局控制的]
          • 4.为了方便配置,使用自定义属性
          • 总结:
        • view的测量
          • 1 view.post(runnalbe)
          • 2.进行测量
          • 案例:
        • api大法好呀

前天看了同事的自定义view博客.也对view的绘制也做一个总结. 高手请指教,小白可以借鉴.

自定义控件

自定义控件:第一步

为了将相同的布局文件在不同的地方使用,不用ctrl+c,ctrl+v,修改时再到处ctrl+f.所以将这个布局文件抽取出来,然后在需要使用的地方引用.

创建文件: layout_two_button.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="match_parent"     android:layout_height="match_parent">     <Button         android:id="@+id/button1"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_gravity="center"         android:layout_weight="1"         android:text="被观察" />      <Button         android:id="@+id/button2"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_gravity="center"         android:layout_weight="1"         android:text="观察" /> LinearLayout> 

在需要的地方引用就可以了

    <include layout="@layout/layout_two_button" /> 
自定义控件:第二步

可是这些布局的点击函数大多相同,为了不在java文件中再设置相同的点击事件,

而xml只是布局文件,不是对象是没有点击事件的.继续将这些抽取出来的文件,变成类对象.

public class ButtonLineLayout extends LinearLayout {     public ButtonLineLayout(Context context, @Nullable AttributeSet attrs) {         super(context, attrs);         View inflate = LayoutInflater.from(context).inflate(R.layout.layout_two_button, this);         inflate.findViewById(R.id.button1).setOnClickListener(v -> Toast.makeText(context, "button1", Toast.LENGTH_SHORT).show());     } } 

将创建的类对象在需要的文件中引用

    <com.ui.material.ButtonLineLayout         android:layout_width="match_parent"         android:layout_height="wrap_content" /> 
自定义控件:总结

说到底,这只不过是一个特殊的lineLayout,里面添加了我们视图,并赋予了点击事件而已。

绘制view视图

小菜开胃,开始正餐。

绘制大小:MeasureSpec

首先来认识一个变量MeaureSpec. MeasureSpec 是一个32位的Int值。

MeasureSpec的前2位是表示测量模式,后面30位是视图的大小。

测量模式
  • exactly : 精确大小。
  • at_most: 限定了最大值。
  • unspecified : 不限制大小。你想多大就多大。一般用不到,忘记它吧。它是你得不到的人。

子view MeasureSpec 是由 父布局的 MeasureSpec 和 自身 布局属性 决定的.

测量模式和wrapCont的关系简单的记:

  • 指定大小 = exactly
  • wrapCOntent= at_most
  • matchParent 视情况而定

Exactly下的matchParent就是Exactly的.
at_most下的matchParent就是at_most .上天注定的

自定义view大杂烩

首先纠正一个误区。textVeiw中的wrap_content可以实现自适应大小,是人家做了代码逻辑处理。

不是把你的view设置了wrap_content也不用管他的大小了。。

它不会孙的铁棒可以你想多大就可以多大。

在源码中view的measure->onMeasure->getDeafultSize方法中可以看到at_most,exactly 没有区别。

哎,不给你看,来打我呀。

开始实践
设置view大小
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {     super.onMeasure(widthMeasureSpec, heightMeasureSpec);      /**      * 获取测量模式和大小      */     int widthMode = MeasureSpec.getMode(widthMeasureSpec);     int widthSpec = MeasureSpec.getSize(widthMeasureSpec);     int heightMode = MeasureSpec.getMode(heightMeasureSpec);     int heightSize = MeasureSpec.getSize(heightMeasureSpec);      /**      * 设置默认值      */     if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {         setMeasuredDimension(23, 23);     }else if(widthMode == MeasureSpec.AT_MOST ){         setMeasuredDimension(23,heightSize);     }else if(heightMode == MeasureSpec.AT_MOST){         setMeasuredDimension(widthSpec,23);     }  } 

总结 :

MeasureSpec.getMode 获取模式

MeasureSpec.getSize 获取大小

setMeasuredDimension 设置view大小

如何自定义view

  • 继承TextView 对view实现功能的扩展
  • 继承Linelayout对viewGroup实现扩展
  • 继承View
  • 继承viewGroup

继承系统控件只是对功能进行扩展,不做过多描述.
下面看如何继承view实现绘制.

1.demo
public class CirecleView extends View {     private int mColor = Color.RED;     private Paint mPaint = new Paint(ANTI_ALIAS_FLAG);           public CirecleView(Context context, @Nullable AttributeSet attrs) {         super(context, attrs);     }          @Override     protected void onDraw(Canvas canvas) {         super.onDraw(canvas);         mPaint.setColor(mColor);         /**          * 画一个圆          */         int width = getWidth();         int height = getHeight();         int radius = Math.min(width, height) / 2;         canvas.drawCircle(width / 2, height / 2, radius, mPaint);              } } 
2.添加wrap_content的支持
public class CirecleView extends View {          ******     ~~~~~~      @Override     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {         super.onMeasure(widthMeasureSpec, heightMeasureSpec);          int widthMode = MeasureSpec.getMode(widthMeasureSpec);         int widthSize = MeasureSpec.getSize(widthMeasureSpec);         int heightMode = MeasureSpec.getMode(heightMeasureSpec);         int heightSize = MeasureSpec.getSize(heightMeasureSpec);          //由一个是精确模式,就取精确模式的值.         if (widthMode == MeasureSpec.EXACTLY || heightMode == MeasureSpec.EXACTLY) {             int size = Math.min(widthSize, heightSize);             setMeasuredDimension(size, size);         } else {             //否则使用默认值             int defaultSize = 400;             setMeasuredDimension(defaultSize, defaultSize);         }      } } 
3.添加padding的支持[margin是由父布局控制的]
@Override protected void onDraw(Canvas canvas) {     super.onDraw(canvas);     mPaint.setColor(mColor);     //首先明确一点,视图的宽高已经固定,padding越大,半径越小     int width = getWidth() - (getPaddingLeft() + getPaddingRight()) ;     int height = getHeight() - (getPaddingTop() + getPaddingBottom()) ;     int radius = Math.min(width, height) / 2;     //然后左,上决定位置     canvas.drawCircle(width / 2 + getPaddingLeft(), height / 2 + getPaddingTop(), radius, mPaint); } 
4.为了方便配置,使用自定义属性

attrs.xml中设置 类,属性,类型

      //类              //属性                        //类型                 
public CirecleView(Context context, @Nullable AttributeSet attrs) {     super(context, attrs);     //获取类下所有的属性     TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CirecleView);     mColor = typedArray.getColor(R.styleable.CirecleView_circle_color, 0xff0000);     typedArray.recycle(); } 
总结:

onMeasure 中添加wrapContent的判断,显示大小

onDraw中添加padding的支持

再提供一些自定义的属性.一个简单的自定义view就完成了

view的测量

我们可以通过setMeasuredDimension来设置view的大小,但是其他view的大小我们如何得知呢.

getWidth()?getMeasureWidth()?

view的绘制和activity中生命周期没有关系。
onResume时,acitivity都可以可见互动了,你还没绘制好,玩我呢。

通常做法:

1 view.post(runnalbe)
view.post(() -> {             view.getMeasuredHeight();                   }); 

补充说明:

getMeasuredHeight 是测量大小,
getHight是布局大小。
一般而言两者没有区别,但是可以有,只不过没啥意义. 【ps:我的面试题,当时一脸懵逼】

重写Layout方法后,测量宽度getMeasuredHeight 会比getHight小100.

    @Override     public void layout(int l, int t, int r, int b) {         super.layout(l, t, r+100, b+100);     } 
2.进行测量

如果是matchParent模式:

在绘制view的时候还不知道父布局的大小,所以无解

如果是wrapContent模式

 //创建一个MeaureSpec:告知view的最大值和测量模式  int heightSpec = weidthSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST)  //给爷去测量  view.measure(weidthSpec,heightSpec)  //获取测量的数值  view.getMeasuredWidth(); 

ps:需要准确的告知测量模式

案例:
        Log.d("test",cire.measuredHeight.toString()) // 0         val widthSpec = MeasureSpec.makeMeasureSpec(resources.getDimension(R.dimen.fab_margin_50).toInt(), MeasureSpec.EXACTLY)         val  heightSpec= MeasureSpec.makeMeasureSpec(Int.MAX_VALUE shr 2, MeasureSpec.AT_MOST)         cire.measure(widthSpec,heightSpec)         Log.d("test",cire.measuredHeight.toString()) // 正确结果131         Log.d("test",cire.height.toString())  // 0  

结果发现getHeight测量后还是0,getMeasureHeight就已经有值了
上面刚说getMeasuredHeight 和 getHight没有区别 ,结果就啪啪的打脸.我不要面子的嘛.-.-


就画一个圈,就说会绘制view了.你在敷衍谁呢,好歹告诉我怎么画一个框呀.好满足你.api大法上!

api大法好呀

借鉴T9的第三个三角的博客,在这里表示感谢.

		/**          * Canvas.drawXXX() 方法,都是以左上角作为基准点的,而 drawText() 却是文字左下方          * Canvas.drawText() 只能绘制单行的文字,而不能换行          * 不能在换行符 n 处换行          * 需要绘制多行的文字可以使用StaticLayout          */         mPaint.setColor(Color.GRAY);         mPaint.setStyle(Paint.Style.STROKE);         mPaint.setTypeface(Typeface.SANS_SERIF);//字体         mPaint.setFakeBoldText(true);//粗体         mPaint.setStrikeThruText(true);//删除线         mPaint.setUnderlineText(true); //下划线         mPaint.setTextSkewX(-0.4f);//倾斜 //        mPaint.setLetterSpacing(0.8f);//字符间距 //        mPaint.setTextAlign(Paint.Align.RIGHT);//对齐         mPaint.setStrokeWidth(5);         mPaint.setTextSize(200);         canvas.drawText("practice",20,200,mPaint);          /**          * 测量text的范围          */         Rect bounds = new Rect();         mPaint.getTextBounds("practice",0,"practice".length(),bounds);         bounds.left += 20;         bounds.right += 20;         bounds.top += 200;         bounds.bottom += 200;         canvas.drawRect(bounds,mPaint);          /**          * 测量text的宽度          */         float textWidth = mPaint.measureText("practice"); //        bounds.width();         canvas.drawLine(20,200, textWidth += 20,200,mPaint);           /**          * 测量高度          */         Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();         float height1 = fontMetrics.descent - fontMetrics.ascent;         float height2 = fontMetrics.bottom - fontMetrics.top;          /**          * 画布裁剪和绘制图片          */         canvas.clipRect(100,100,400,400);         Bitmap bitmap =   BitmapFactory.decodeResource(getResources(), R.drawable.ic_action_name);         canvas.drawBitmap(bitmap,100,100,mPaint);          /**          * 按路径裁剪          */         Path path = new Path();         path.addCircle(500,500,400, Path.Direction.CCW);         canvas.clipPath(path);          /**          * 平移          */         canvas.translate(300,100);          /**          * 旋转 图层          */         canvas.rotate(200);          /**          * 缩放          */         canvas.scale(1.5f,0.8f,100,100);          /**          * 画圈          */         canvas.drawCircle(20, 20, 4, mPaint);         /**          * 画矩形          */         canvas.drawRect(20,0,20,90,mPaint); 


推荐阅读
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
author-avatar
艳斐儿M
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有