android自定义控件笔记

概述

自定义控件类别
  • 继承已有控件进行拓展
  • 组合已有控件进行拓展

View和ViewGroup的区别


自定义控件创建步骤
  1. 测量(onmeasure(),如果自定义控件继承了已有的viewGroup(如:frameLayout),那么不需要自己实现,继承的viewGroup会自动实现)
  2. 布局(onlayout(),只有在自定义ViewGroup才使用)
  3. 绘制(ondraw(),自定义ViewGroup并不需要)

滑动开关(继承自View)

原理
  • 自定义控件:继承方式
    • 原理两个图片,通过控制上面图片移动来达到效果
    事例: 

实现onmeasure()


实现ondraw()

注: 
invalidate()可以让ondraw()重新绘制,用于刷新视图


处理触摸

原理:

  1. 实现触摸方法,获取当前X
  2. 把X作为ondraw()中canvas.drawBitmap()中x的位置
  3. 通过触摸事件的move来不断invalidate()来刷新视图

处理menu点击事件
  1. 重写onKeyDown方法 

  2. 通过if判断按键标示 
     

    注: 
    return true拦截事件,自定义处理

  3. 进一步处理…..


自定义下拉选择

原理

效果图:

原理:组合editText和一个三角图片以及一个listView,当点击图片时,通过如下方法来实现:

注:

  • showAsDropDown方法在指定的控件下显示
  • 三个参数:指定显示的view,以及view的x,y的偏移量
  • 记得判断popupWindow是否存在: 

处理点击和删除
去除listView的滚动条属性和设置背景


点击及删除

注:删除后,不要忘记调用notifyDataSetChanged来更新view。


view视图实时更新

解决view高度实时更新和没有项目时消失


下拉标志隐藏

在项目为零时,需要同时隐藏下拉图片


解决popupWindow焦点获取
设置点击外部

popupWindow默认不获取点击焦点 
需要设置为:true


点击项目传值到文本框中


注意

解决方案:

  • 尽量不在在listView中使用以上控件
  • 如果必须使用的话,需要在listView的item布局的根布局添加如下属性: 

    设置之后,button获取焦点,item中其它控件也可以获取焦点

轮播图(ViewPager)

pagerAdpter

viewPager的数据适配器 
必须 实现:

  • getCount() //view数目
  • isViewFromObject() //判断是否新建view
  • destroyItem() //销毁过载view 

  • instantiateItem() //设置数据源


判断是否需要去创建(true:不创建,使用缓存): 

注:最多会缓存3个view视图


ellipsize属性

textView中设置文字超过控件显示区域省略号位置的属性


轮播图下面标识点

实现:使用view包含图片排列实现 

代码: 


实现轮播图无限循环(伪)

原理:使用取余的方法: 

值为: 

注: 
在PagerAdapter的继承类的getCount中返回整数的最大值,来与数据list的项数求余,实现无限循环,由于这种循环有极限,但几乎不可能到极限,但在数学这不是无限但趋近于无限,可以称之为伪无限循环。


解决反向滑动问题

思路:把原来取得整数最大值取一半,通过设置viewPager的setCurrentItem方法把viewpager的项设在一半,为了进一步解决值可能不是第一项(即取余数不为0),需要做如下处理: 


解决自动循环的问题

思路:使用hander来解决:在初始化时通过延时发送

sendEmptyMessageDelayed(int what, long delayMillis)

来循环滑动视图,然后进行递归来无限自动循环(不必担心循环完:1 year = 31536000s)


下拉刷新

 
  
  
  1. public class MyListView extends ListView {
  2. public MyListView(Context context)
  3. {
  4. super(context);
  5. init();
  6. }
  7. public MyListView(Context context, AttributeSet attrs) {
  8. super(context, attrs);
  9. init();
  10. }
  11. private void init(){
  12. }
  13. }

注:在实现继承空间时,不要忘记重写构造函数(为此曾经找了一天bug╮(╯_╰)╭)特别是public MyListView(Context context, AttributeSet attrs)


 
  
  
  1. View.inflate(this, R.layout.layout_header, null);
  2. myList.addHeaderView(headerView);

注:该view的添加需要在setAdapter方法前执行


getHeight和getMeasuredHeigght区别

  • getHeight()可以使用监听器来监听view是否渲染完成
  • 自定义控件中主要使用getMeasuredHeight()

使用getMeasuredHeight


下拉逻辑:通过触摸检测来设置pading 
只用在if (paddingValue > -heightView && getFirstVisiblePosition() == 0)即下拉值小于headerView的高度且可见项为第一个时。

 
  
  
  1. case MotionEvent.ACTION_MOVE:
  2. int onMoveY = (int) ev.getY();
  3. int distanceY = onMoveY - onDownY;
  4. int paddingValue = -heightView + distanceY;
  5. System.out.println("paddingValue的值为:" + paddingValue);
  6. if (paddingValue > -heightView && getFirstVisiblePosition() == 0) {
  7. headerView.setPadding(0, paddingValue, 0, 0);
  8. System.out.println("touch_move");
  9. return true;
  10. }

通过状态码来更新UI

主要的三种状态:

  • 下拉刷新
  • 松手刷新
  • 正在刷新

注:如果控件附加了动画效果的话,在进行操作的时候最好先清除动画: iv_pull.clearAnimation(); 
因为操作可能与动画产生冲突


注:不要忘记处理refreshing状态下触摸事件

如下:

 
  
  
  1. case MotionEvent.ACTION_MOVE:
  2. //如果处于正在刷新状态,操作失效
  3. if (mCurrent == REFRESHING_REFRESH) {
  4. break;
  5. }

获取当前时间
 
  
  
  1. private String getCurrentTime() {
  2. SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
  3. return sdf.format(new Date());
  4. }

注:yy-MM-dd 这些大小写不能错!! 
该方法要放到刷新完成时 
代码: 
getCurrentTime.java


定时阻塞线程代码: 
定时阻塞线程.java


滑动状态监听

状态码:

 
  
  
  1. /**
  2. * The view is not scrolling. Note navigating the list using the trackball counts as
  3. * being in the idle state since these transitions are not animated.
  4. */
  5. //闲置状态,手指松开瞬间
  6. public static int SCROLL_STATE_IDLE = 0;
  7. /**
  8. * The user is scrolling using touch, and their finger is still on the screen
  9. */
  10. //手指滑动中
  11. public static int SCROLL_STATE_TOUCH_SCROLL = 1;
  12. /**
  13. * The user had previously been scrolling using touch and had performed a fling. The
  14. * animation is now coasting to a stop
  15. */
  16. //快速滑动状态,快速滑动后松开瞬间
  17. public static int SCROLL_STATE_FLING = 2;
尾部显示原理

在拉到最后一个数据项且手指滑动松开

注:setSelection()设置listView选中项,以1开头。可以显示到选中项的地方,选中项一般(如果可以)位于屏幕第一项。


注:listview.add()在最后追加项目



侧栏自定义(继承自ViewGroup)

三方库

github:SlidingMenu


自定义控件实现步骤


View和viewGrup的区别


drawablePadding

注:drawablePadding设置drawable图片与文本之间的距离 
java 
android:drawablePadding="15dp" 

drawableLeft:在控件左边显示图片资源 
right,top等相似


标题栏高度

注:常见标题栏高度为55dp-60dp之间


关于控件的gravity属性(textview.gravity)

指设置控件内部的子项目,所以textview的gravity设置会对textview的text属性起作用,因为text是textview


控件大小(dp,sp,px)

文字的尺寸一律用sp单位,非文字的尺寸一律使用dp单位。例如textSize="16sp"、layout_width="60dp";偶尔需要使用px单位,例如需要在屏幕上画一条细的分隔线时


onFinishInflate()


getLayoutParams()

getLayoutParams().width 
getLayoutParams().height

注:通过view的getLayoutParams()方法可以获取高和宽,在onmeasure中使用,如: 


viewgroup的onlayout()

用来设置子view在viewGroup中的位置

注:在该函数中子view的layout()方法中的四个函数分别是子view的左上角和右下角坐标。


viewgroup的onmeasure()

该函数传入的宽和高是viewgroup自身的数据


让控件移动的方法
  • 在viewgroup中可以通过layout()来不断改变位置来移动。
  • offsetTopAndBottom(offset)和offsetLeftAndRight(offset)
  • scrollTo()和scrollBy()

关于scrollTo()和scrollBy()

注:scrollTo()移动的不是ViewGroup而是可视视图,就是眼睛看到的屏幕。 
见: 
Android scrollTo() scrollBy() Scroller讲解及应用 - 推酷

注:scrollTo()移动是瞬间的,并没有附加动画效果


关于实现onmeasure方法


实现侧滑动画
1.自定义动画实现

2.scroller实现
  1. 实例化scroller()对象
  2. 使用startscroll来控制移动
  3. 调用invalidate()刷新

注:


触摸事件分发机制

解决触摸冲突问题

通过判断移动值(X > 某移动值),来改变onInterceptTouchEvent的返回值(true或false)来决定是否拦截触摸事件。

事例: 

猜你喜欢

转载自blog.csdn.net/lxxlxx888/article/details/54095483