zoukankan      html  css  js  c++  java
  • [转]抽屉 Panel 研究

    大家对抽屉控件的第一反应就是系统提供的 如下:

    其实 该控件的原理说白了 很简单 即:

    * ViewGroup 如:LinearLayout 用于放置各种View

    * Button 用于 展开/收起 ViewGroup

    所以该控件的大致布局应如下:

    Java代码 收藏代码

    1. <Panel> 
    2. <Button /> 
    3. <LinearLayout > 
    4.     <TextView /> 
    5.     <ImageView /> 
    6. </LinearLayout> 
    7. </Panel> 

    为了降低开发难度 我打算 定义 Panel extends LinearLayout

    [代码 步骤]

    1. 定义一些XML用到的属性

    Xml代码 收藏代码

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <resources>
    3. <declare-styleable name="Panel">
    4.          //动画演变时长 
    5. <attr name="animationDuration" format="integer" />
    6.         //摆放位置 只能取下面的4个值 
    7. <attr name="position">
    8. <enum name="top" value="0" />
    9. <enum name="bottom" value="1" />
    10. <enum name="left" value="2" />
    11. <enum name="right" value="3" />
    12. </attr>
    13.         //开合是否有动画效果 
    14. <attr name="animationEnable" format="boolean" />
    15. </declare-styleable>
    16. </resources>

    2. 一个标准的XML为:

    Xml代码 收藏代码

    1. <org.panel.Panel
    2. android:id="@+id/leftPanel"
    3. android:layout_width="wrap_content"
    4. android:layout_height="wrap_content"
    5. panel:position="left"
    6. panel:animationDuration="10"
    7. panel:animationEnable="true"
    8. android:layout_gravity="left"
    9. >
    10. <Button
    11. android:layout_width="wrap_content"
    12. android:layout_height="wrap_content"
    13. />
    14. <LinearLayout
    15. android:orientation="vertical"
    16. android:layout_width="wrap_content"
    17. android:layout_height="wrap_content"
    18. >
    19. <CheckBox
    20. android:layout_width="fill_parent"
    21. android:layout_height="wrap_content"
    22. android:text="Top Panel!"
    23. android:textSize="16dip"
    24. android:textColor="#eee"
    25. android:textStyle="bold"
    26. />
    27. <EditText
    28. android:layout_width="200dip"
    29. android:layout_height="wrap_content"
    30. />
    31. <Button
    32. android:layout_width="100dp"
    33. android:layout_height="wrap_content"
    34. android:text="OK!"
    35. />
    36. </LinearLayout>
    37. </org.panel.Panel>

    3. 解析该XML 并设置之

    Java代码 收藏代码

    1. public Panel(Context context, AttributeSet attrs) { 
    2. super(context, attrs); 
    3.         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Panel); 
    4.         mDuration = a.getInteger(R.styleable.Panel_animationDuration, 750); 
    5.         mPosition = a.getInteger(R.styleable.Panel_position, BOTTOM); 
    6.         isAnimation = a.getBoolean(R.styleable.Panel_animationEnable, true); 
    7.         a.recycle(); 
    8. //根据mPosition 决定LinearLayout的android:orientation属性
    9.         mOrientation = (mPosition == TOP || mPosition == BOTTOM)? VERTICAL : HORIZONTAL; 
    10.         setOrientation(mOrientation); 
    11. //初始化mHandle 背景图
    12.         initialHandlerBg(); 
    13.     } 

    4. 设定Button 背景图

    Java代码 收藏代码

    1. //设置mHandle所用背景图   
    2. private void initialHandlerBg(){ 
    3. if(mPosition == TOP){ 
    4.             mOpenedHandle = getResources().getDrawable(R.drawable.top_switcher_expanded_background); 
    5.             mClosedHandle = getResources().getDrawable(R.drawable.top_switcher_collapsed_background); 
    6.         } 
    7. else if(mPosition == BOTTOM) { 
    8.             mOpenedHandle = getResources().getDrawable(R.drawable.bottom_switcher_expanded_background); 
    9.             mClosedHandle = getResources().getDrawable(R.drawable.bottom_switcher_collapsed_background); 
    10.         } 
    11. else if(mPosition == LEFT) { 
    12.             mOpenedHandle = getResources().getDrawable(R.drawable.left_switcher_expanded_background); 
    13.             mClosedHandle = getResources().getDrawable(R.drawable.left_switcher_collapsed_background); 
    14.         } 
    15. else if(mPosition == RIGHT) { 
    16.             mOpenedHandle = getResources().getDrawable(R.drawable.right_switcher_expanded_background); 
    17.             mClosedHandle = getResources().getDrawable(R.drawable.right_switcher_collapsed_background); 
    18.         } 
    19.     } 

    5. 取出其中的 ViewGroup & Button

    Java代码 收藏代码

    1. //回调函数 界面初始化快结束时调用 用于得到 mHandle/mContent
    2. protected void onFinishInflate() { 
    3. super.onFinishInflate(); 
    4. //得到mHandle实例
    5.         mHandle = this.getChildAt(0); 
    6. if (mHandle == null) { 
    7. throw new RuntimeException("Your Panel must have a View - mHandle"); 
    8.         } 
    9.         mHandle.setOnClickListener(clickListener); 
    10. //得到mContent实例
    11.         mContent = this.getChildAt(1); 
    12. if (mContent == null) { 
    13. throw new RuntimeException("Your Panel must have a View - mContent"); 
    14.         } 
    15. //先移除mHandle/mContent 然后根据position决定二者的添加次序
    16.         removeView(mHandle); 
    17.         removeView(mContent); 
    18. if (mPosition == TOP || mPosition == LEFT) { 
    19.             addView(mContent); 
    20.             addView(mHandle); 
    21.         } else { 
    22.             addView(mHandle); 
    23.             addView(mContent); 
    24.         } 
    25. if (mClosedHandle != null) { 
    26.             mHandle.setBackgroundDrawable(mClosedHandle); 
    27.         } 
    28. //隐藏 mContent
    29.         mContent.setVisibility(GONE); 
    30.     } 

    6. 得到ViewGroup 宽度/高度 以决定动画演变范围

       注意其位置 并非放在开始地方 因为那时候返回值都是0

    Java代码 收藏代码

    1. @Override //回调函数 此时其内所有子View 宽度/高度 都已确定
    2. protected void onLayout(boolean changed, int l, int t, int r, int b) { 
    3. super.onLayout(changed, l, t, r, b); 
    4.         mContentWidth = mContent.getWidth(); 
    5.         mContentHeight = mContent.getHeight(); 
    6.         paddingTop = this.getPaddingTop(); 
    7.         paddingLeft = this.getPaddingLeft(); 
    8.     } 

    7.  定义Button 响应事情 执行 开合ViewGroup

    Java代码 收藏代码

    1. // 定义mHandle监听器 用于开合mContent
    2.     OnClickListener clickListener = new OnClickListener(){ 
    3. public void onClick(View v) { 
    4. // TODO Auto-generated method stub
    5. if(!isContentExpand){ 
    6.                 open(); 
    7.             } 
    8. else { 
    9.                 close(); 
    10.             } 
    11. //置反 即:开-合-开-合-开-...
    12.             isContentExpand = !isContentExpand; 
    13.         } 
    14.     }; 

    8. 定义开合的回调函数 具体效果 见:setOnClickListener(OnClickListener listener)

    Java代码 收藏代码

    1. //回调函数 用于监听 Panel 的开合 效果见:setOnClickLstener(OnClickListener listener)
    2. public static interface OnPanelListener { 
    3. //- open
    4. public void onPanelOpened(Panel panel); 
    5. //- close
    6. public void onPanelClosed(Panel panel); 
    7.     } 

    10. 开 即: 打开ViewGroup

    Java代码 收藏代码

    1. public void open(){ 
    2. if(isAnimation){ 
    3.             doAnimationOpen(); 
    4.         } 
    5. else { 
    6.             doOpen(); 
    7.         } 
    8.     } 
    9. public void doOpen(){ 
    10.         mContent.setVisibility(VISIBLE); 
    11.     } 
    12. public void doAnimationOpen(){ 
    13.         mContent.setVisibility(VISIBLE); 
    14.         post(aOpen); 
    15.     } 

    11. 定义开的Animation

    Java代码 收藏代码

    1. //- open
    2.     Runnable aOpen = new Runnable() { 
    3. public void run() { 
    4.             TranslateAnimation animation; 
    5. int fromXDelta = 0, toXDelta = 0, fromYDelta = 0, toYDelta = 0; 
    6. int calculatedDuration = 0; 
    7. if(mPosition == TOP){ 
    8.                 fromYDelta = -1 * mContentHeight; 
    9.                 toXDelta = 0; 
    10.                 calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight; 
    11.             } 
    12. else if(mPosition == BOTTOM){ 
    13.                 fromYDelta = paddingTop; 
    14.                 toYDelta = fromYDelta + 1 * mContentHeight; 
    15.                 calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight; 
    16.             } 
    17. else if(mPosition == LEFT){ 
    18.                 fromXDelta = -1 * mContentWidth; 
    19.                 toXDelta = 0; 
    20.                 calculatedDuration = mDuration * Math.abs(toXDelta - fromXDelta) / mContentWidth; 
    21.             } 
    22. else if(mPosition == RIGHT){ 
    23.                 fromXDelta = paddingLeft; 
    24.                 toXDelta = fromYDelta + 1 * mContentHeight; 
    25.                 calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight; 
    26.             } 
    27.             animation = new TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta); 
    28.             animation.setDuration(calculatedDuration); 
    29.             animation.setAnimationListener(aOListener); 
    30.             startAnimation(animation); 
    31.         } 
    32.     }; 

    12. 合 即:关闭ViewGroup

    Java代码 收藏代码

    1. public void close(){ 
    2. if(isAnimation){ 
    3.             doAnimationClose(); 
    4.         } 
    5. else { 
    6.             doClose(); 
    7.         } 
    8.     } 
    9. public void doClose(){ 
    10.         mContent.setVisibility(GONE); 
    11.     } 
    12. public void doAnimationClose(){ 
    13.         post(aClose); 
    14.     } 

    13. 定义合的Animation

    Java代码 收藏代码

    1. //- close
    2.     Runnable aClose = new Runnable() { 
    3. public void run() { 
    4.             TranslateAnimation animation; 
    5. int fromXDelta = 0, toXDelta = 0, fromYDelta = 0, toYDelta = 0; 
    6. int calculatedDuration = 0; 
    7. if(mPosition == TOP){ 
    8.                 toYDelta = -1 * mContentHeight; 
    9.                 calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight; 
    10.             } 
    11. else if(mPosition == BOTTOM){ 
    12.                 fromYDelta = 1 *  mContentHeight; 
    13.                 toYDelta = paddingTop; 
    14.                 calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight; 
    15.             } 
    16. else if(mPosition == LEFT){ 
    17.                 toXDelta = -1 * mContentWidth; 
    18.                 calculatedDuration = mDuration * Math.abs(toXDelta - fromXDelta) / mContentWidth; 
    19.             } 
    20. else if(mPosition == RIGHT){ 
    21.             } 
    22.             animation = new TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta); 
    23.             animation.setDuration(calculatedDuration); 
    24.             animation.setAnimationListener(aCListener); 
    25.             startAnimation(animation); 
    26.         } 
    27.     }; 

    14. 定义二者Animation 的回调函数 即:结束后 更改Button背景图 通知OnPanelListener

    Java代码 收藏代码

    1. //善后工作 比如:改变mHandle背景图 通知开合监听器
    2. private void postProcess() { 
    3. // to update mHandle 's background
    4. if (!isContentExpand ) { 
    5.             mHandle.setBackgroundDrawable(mClosedHandle); 
    6.         }  
    7. else { 
    8.             mHandle.setBackgroundDrawable(mOpenedHandle); 
    9.         } 
    10. // invoke listener if any
    11. if (panelListener != null) { 
    12. if (isContentExpand) { 
    13.                 panelListener.onPanelOpened(Panel.this); 
    14.             } 
    15. else { 
    16.                 panelListener.onPanelClosed(Panel.this); 
    17.             } 
    18.         } 
    19.     } 

    15. emulator 运行截图:

    * 先贴其布局

    Xml代码 收藏代码

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3. xmlns:panel="http://schemas.android.com/apk/res/org.panel"
    4. android:layout_width="fill_parent"
    5. android:layout_height="fill_parent"
    6. android:orientation="vertical"
    7. >
    8. <org.panel.Panel
    9. android:id="@+id/leftPanel"
    10. android:layout_width="wrap_content"
    11. android:layout_height="wrap_content"
    12. panel:position="left"
    13. panel:animationDuration="10"
    14. panel:animationEnable="true"
    15. android:layout_gravity="left"
    16. >
    17. <Button
    18. android:layout_width="wrap_content"
    19. android:layout_height="wrap_content"
    20. />
    21. <LinearLayout
    22. android:orientation="vertical"
    23. android:layout_width="wrap_content"
    24. android:layout_height="wrap_content"
    25. >
    26. <CheckBox
    27. android:layout_width="fill_parent"
    28. android:layout_height="wrap_content"
    29. android:text="Top Panel!"
    30. android:textSize="16dip"
    31. android:textColor="#eee"
    32. android:textStyle="bold"
    33. />
    34. <EditText
    35. android:layout_width="200dip"
    36. android:layout_height="wrap_content"
    37. />
    38. <Button
    39. android:layout_width="100dp"
    40. android:layout_height="wrap_content"
    41. android:text="OK!"
    42. />
    43. </LinearLayout>
    44. </org.panel.Panel>
    45. <org.panel.Panel
    46. android:id="@+id/rightPanel"
    47. android:layout_width="wrap_content"
    48. android:layout_height="wrap_content"
    49. panel:position="right"
    50. panel:animationDuration="10"
    51. panel:animationEnable="true"
    52. android:layout_gravity="right"
    53. >
    54. <Button
    55. android:layout_width="wrap_content"
    56. android:layout_height="wrap_content"
    57. />
    58. <LinearLayout
    59. android:orientation="vertical"
    60. android:layout_width="wrap_content"
    61. android:layout_height="wrap_content"
    62. >
    63. <ImageView
    64. android:layout_width="wrap_content"
    65. android:layout_height="wrap_content"
    66. android:src="@drawable/beijing4_b"
    67. />
    68. </LinearLayout>
    69. </org.panel.Panel>
    70. <LinearLayout
    71. android:layout_width="fill_parent"
    72. android:layout_height="wrap_content"
    73. android:orientation="vertical"
    74. >
    75. <TextView
    76. android:layout_width="fill_parent"
    77. android:layout_height="wrap_content"
    78. android:textSize="16dip"
    79. android:textColor="#ddd"
    80. android:text="other area!!!!!!!!"
    81. />
    82. <Button
    83. android:id="@+id/button"
    84. android:layout_width="100dp"
    85. android:layout_height="wrap_content"
    86. android:text="Yes!"
    87. />
    88. </LinearLayout>
    89. </LinearLayout>

    * 运行截图:

    - 开

    - 合

  • 相关阅读:
    适配器模式(2)
    设计模式之6大设计原则(1)
    Mybatis框架基础支持层——反射工具箱之MetaClass(7)
    Mybatis框架基础支持层——反射工具箱之实体属性Property工具集(6)
    Mybatis框架基础支持层——反射工具箱之对象工厂ObjectFactory&DefaultObjectFactory(5)
    Mybatis框架基础支持层——反射工具箱之泛型解析工具TypeParameterResolver(4)
    Guava动态调用方法
    数据库的数据同步
    springboot(二十二)-sharding-jdbc-读写分离
    springboot(二十一)-集成memcached
  • 原文地址:https://www.cnblogs.com/GnagWang/p/2092411.html
Copyright © 2011-2022 走看看