• 自定义控件基础01_菜单轮__viewPager_下拉框_自定义开关


    1,自定义控件分类:

    1.1组合控件:由安卓中原生的控件组合起来,配合动画达成的效果

    1.2自定义控件

    1.3组合控件案例演示:

    案例:优酷菜单demo

     

    三层圆环,按下menu键会通过动画效果消失在界面,点击小房子和中层圆环,最外层圆环消失

    ①布局实现:

    三层相对布局相互叠加(因为图片背景是透明的,所以可以叠加显示)

    由于三个布局是叠加显示的,所以这个菜单选项要使用一个占据焦点比较强的(不然有可能点击不到)ImageButton控件

    控件上background=”@android:color/transparent”//透明色

    ②动画效果,三级菜单的隐藏和显示

    动画效果,点击二级菜单,三级菜单旋转消失,再次点击旋转回来显示

    每一层实际上是一个正方形(圆环在一个背景透明的正方形上),那么只要它做自身的的旋转,就能起到圆环旋转动画的实现,从界面消失,即以底部居中为中心左旋转180度,从界面出现,即以底部居中为中心右旋转180度,就能实现这个效果.

    am.setFillAfter()//设置控件保持在动画结束的状态

    am.setStartOffset()//设置延迟执行动画

    一级菜单的主要是控制二级菜单,如果三级菜单也存在就一起控制,三级菜单先消失,二级菜单延迟消失.但是再次点击一级菜单并不会返回三级菜单

    点击menu按钮,三个菜单全部消失,延迟有序

    ③额外:动画播放完了,圆环隐藏了,但是还可以被点击,在执行隐藏的时候设置按钮不可用

    setEnable()//设置是否可用

     动画没播放完就再次点击会终止未执行完的动画,所以,在执行隐藏或显示的动画时,设置一个监听器,如果动画播放完了,才能运行执行下一个动画(定义一个变量控制播放动画的数量)

    1.4 ViewPager android3.0版本就已经含有此控件(实现图片轮播效果)

    Support-v4.jar包包含了ViewPager控件,低版本就可以使用这个控件了

     

    低版本开发的时候,导入viewPager,拷贝全类名使用该控件(类似自定义控件)

    在布局文件中的颜色#66(透明度)66(R)66(G)66(B)

    viewPager用法

    ①根据需求创建imageView的数量,并填充数据,设置图片

    ②viewPager.setAdapter(PagerAdapter)//设置对应的适配器就行了

    如果适配器类参数名异常(argxx)需要导入源码(如果点入类之后找不到导入源码的按钮,就卸载v4包重新add一下,就能导入源码了)

    源码路径sdk/extras/android/support/v4/src/java

    适配器类中的几个重要方法

    getCount()//返回的条目数

    isViewFromObject(xx,xx) //判断是否使用缓存,如果返回的是true,使用缓存,不去调用instantiXX方法创建一个新对象,

    简单来说:如果用户未滑动出界,该图片对象不改变,是否需要重新初始化一个对象来显示.

    返回值推荐写法view==object//如果是一个对象就使用缓存,如果不是就创建一个新的

    instantiateItem()//初始化一个条目

    预加载功能:会预加载左右两张图片,即初始化左右两张图片

    //初始化一个条目,把position对应的imageView添加到ViewPager中

    viewPager.addView(imageViewList.get(position));

    返回这个view;

    destoryItem()//销毁一个条目,position当前被销毁的索引

    //移除掉ViewPager中的ImageView

    viewPager.removeView(imageViewList.get(position));

    额外:如果出现找不到方法,但工程内又确实有jar包,去查配置build path,打钩即可

    1.4.2 图片轮播的进度点和图片描述数组的实现

    ①在循环添加图片的时候,也给进度点对应的父控件添加一个小点,开发中有美工做,这里通过xml.

    小圆点的创建

    创建shape节点的xml文件

    shape属性:shape=”oval” //圆形

    子节点corners //弧度5dp即可

     Solid  //固定颜色

    //记得要创建两个,一个带焦点,一个不带焦点的

    ②添加的时候,记得设置对应参数 设置宽高

    View v = new (this)

    v.setBacKGxxxxx(id);

    LayoutParams params = new xxxx(w,h)//设置宽高

    Params.xxxx//可以设置对应的参数,控件间的距离,设置是否被选中(设置一个状态选择器可以实现切换进度小圆点的效果)

    v.setLayoutParams(params);//设置参数,必须要设置参数,否则无法显示

    //最后添加进Linerlayout中

    ③图片描述信息的数据索引要匹配上适配器的图片数据

    额外:设置默认的选中点,注意代码的顺序,要在设置完数据之后设置.

    ④根据viewPager切换状态来更改进度点状态和信息显示

    viewPager.setOnPageChangeListener(this)//设置页面切换监听器

    两个方法

    onPageSelected()//当页面被选中(完全显示)的时候,触发此方法

    更改进度点父节点的子节点集合中子孩子(进度点的状态)

    更改文描述文本的显示

    别忘了修改前一个节点的状态(拿个引用记录它,如果position直接+-的话,容易逻辑混乱)

    onPageScrolled()//当页面卷曲的时候调用

    1.4.3 伪无限循环和动态切换

    ①viewPager移动到第一个(0)或者最后一个的时候(最大索引),

      就不会预加载上一个(-1)或 下一个(最大索引+1)了

    所以,让返回的count很大就行(比如2g-1(Integer.Max_Value))(数学小技巧)

    那么对应的索引就是count%集合长度//相当于倍数取余,可以对应到指定的索引

    额外:初始化的时候,把默认选中的点为返回的count中间的值(这样↔滑动都不会出现停滞阻塞的情况了),要让选中的点在第一个位置,就让中间值再减去倍数取余

    pageView.setCurrentItem()//设置默认选中的坐标

    额外:设置默认选中点,实际上是调用了onPageSelected()方法,记得调换前一个点和当前点设置的位置,因为一开始这样两个都是0,所以要在后面要设置为选中.在前面的设置为未选中.

    ②动态切换

    开启一个子线程,定期切换viewPager的图片(这是一个修改ui的操作).

    但要注意的是,子线程在activity中不会被直接销毁,activity的ondestory()方法中设置一个变量去控制这个无限循环

    额外:休眠的操作放到循环最后,就不会多输出一次(因为变量控制的时候,它如果已经睡眠了,还会多输出一次,所以这也算一个小优化)

    2 组合控件:下拉选择框(ListView填充),参考效果:

     

    2.1参考布局:

    点击向下的箭头,出现下拉框,点击下拉框选项会把对应的号码填充到输入框中

    下拉框实际上是popupWindow,内容是一个ListView

    设置一个适配器,填充数据

    把listView添加到popupWindow上面

    PopupWindow pw = new PopupWindow(listview,w,h);

    W:宽度:输入框的宽度,et.getWidth();

    H;高度:整个屏幕都可以,设死也可以

    //显示在界面上,显示在某个控件下

    pw.showAsDropDown(输入框,偏移量x,偏移量y)

    2.2 细节问题

    ①外形边框是listView的背景图片

    ②listView.setVerticalScrollBarEnable()//设置是否显示右侧垂直滑动条

    如果全部条目都被删除了,就应该关闭popup.

    ③Button,imagebutton,checkbox这一类控件抢焦点能力都很强.

    PopupWindow本身是不可以使用焦点的,设置可以使用焦点,不生效

    原因:子条目的button或imageButton把焦点抢走了

    //设置子控件不可以抢占父元素的事件,但是可以以块去分配事件

    解决:给子条目LinearLayout布局:descendantFocusablity=”blocksDescXXX”

    ④popupWindow跟输入框之间有细微的空白

    因为输入框本身是有边框宽度的,而获取的输入框宽度不包含它,所以稍微减少一点就行.

    ⑤点击其它地方也要让它会被关闭

    popupWindow.setOutsideTouchable()//点击外部可以被关闭,单独设置不生效

    popupWindow.setBackground(xxxx)//设置一个背景,才能让上面的设置生效

    3.自定义控件(前面都是组合控件)

    3.1 滑动开关,参考效果图,拖动方块可以实现开关切换

     

    ①安卓中每一个控件或者布局都是继承自View类(控件的爸爸),创建一个类去继承View

    需要重写的构造方法

    如果要在java中new出来,就重写只有Context 的构造

    如果要在 布局文件中引用自定义控件时,使用有Context和atts的构造

    一般两个都写.

    ②拷贝对应的图片

    创建方法(都是公开,调用者可自定义,从这一角度考虑自定义控件功能的实现),

    设置背景图片setSwitchBackgorundResource()//这个名字更容易理解,

    设置滑动块的图片

    设置当前开关的默认状态.

    用对应的成员变量去记录下来,方便在绘制的时候处理.

    ③自定义控件的绘制

    android中View的绘制流程

    不要直接去覆盖,使用谷歌提供的回调接口

    Measure(测量宽高信息) >>>Layout(排版/布局,包含子控件) >>>draw(绘制)

    onMeasure(当测量时调用)>>>onLayout(布局时回调) >>>onDraw(当绘制时)

    3.2 绘制控件

    ①在onMeasure方法中测量并设置自己的宽和高

    重写onMeasure(xxx)方法

    设置宽高和背景图片的宽和高一致

    setMeasureDimension(w,h);//设置测量后的宽高

    super.xxx要在最前面,不然不能生效

    ②没有子控件,不需要onLayout回调,在onDraw()方法中,把开关绘制出来

    重写onDraw(Canvas)方法,super.onDraw()//可以删除掉

    Canvas 画板,使用canvas所画出来的东西,都是作为当前控件,在屏幕上显示

    //把背景图片平铺在当前控件上

    Canvas.drawBitMap(图片,左,上,画笔)//0,0(左上角),null(绘制图片不需要画笔)

    //根据当前状态currentState(成员变量)来绘制滑动块状态

    如果为true,绘制在背景图片右边(左边距为背景宽减去开关宽,上边距为顶部0即可)

    如果为false,绘制在背景图片的左边(左边距为0,上边距起点0即可)

    3.3触摸移动改变状态

    ①重写onTouchEvent()//返回值为true消耗当前事件,自己处理,返回为false交给别人处理.

    ②判断事件类型

    观察可知,移动的时候只改变X 轴值

    记录按下的点,移动时候的点,两者的x轴值相减就是位移范围(正数向左,负数向右).

    如果采用这种办法,需要记录下初始的位置,再对其进行修改

    实际上,直接用移动的点数值给左边距设置数值即可.

    当移动的点发生改变的时候,手动触发onDraw方法的重绘.

    invaliadte()//刷新当前控件,会引起onDraw方法的调用.

    ③在onDraw()方法里,根据X轴的值来动态的修改滑动块的位置

    Canvas.drawBitMap(滑动块图片,左边距,0上边距不变,null不需要画笔);

    3.3.2用户体验问题

    ①会移出边界

    限定宽度,滑动块的左边距不能小于0,如果小于0,绘制的时候就一直设置为0

    左边距(滑动块的左边距)同样也不能大于(背景图片的宽度-滑动块的宽度),

    如果大于,就一直为两者之差.

    ②移动的时候,如果在中间松开,不会自动归位

    先判断是否在滑动中(不然滑动的时候就会直接跳位,体验不好)

    松开的时候(设置为不在滑动中),根据左边距的值判断状态

    如果不在滑动中,两种方法

    (判断滑动块的左边距是否大于整个背景图片的四分之一,

    如果大于就代表用户想要关闭它,如果小于就代表用户想要开启它.根据结果跳位)

    (或者滑动块的中心点和背景图片的中心点值的比较,

    如果滑动块中心点>背景图片中心点值,当前状态重置为true,打开的状态

    如果小于,就重置为 false,关闭的状态

    )

    ③手指按下位置与用户预期不一样(用户希望的是移动的点是中间的点,而实际上是按下的点)

    重新绘制的时候,左边距的数值>>调整>>左边距减去滑动块宽度的一半.

    最后再对这个数据进行判断.

  • 相关阅读:
    ABAP Webdynpro Interface View的用法
    ABAP Webdynpro的跟踪工具WD_TRACE_TOOL
    git 速查
    Python 解析含有命名空间(xmlns)的xml文件(基于ElementTree)
    完全显示DataFrame中行、列内容
    解决Jupyter Notebook中for循环输出DataFrame不够美观
    git配置别名
    元素可拖拽(移动端与pc端)
    pointer network和recursive神经网络
    ELMO,BERT和GPT简介
  • 原文地址:https://www.cnblogs.com/adventurer/p/5642026.html
Copyright © 2020-2023  润新知