zoukankan      html  css  js  c++  java
  • 抽屉Panel的研究

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

     

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

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

    * Button 用于 展开/收起 ViewGroup

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

    Java代码  收藏代码
    1. <Panel>  
    2.   
    3. <Button />  
    4.   
    5. <LinearLayout >  
    6.     <TextView />  
    7.     <ImageView />  
    8. </LinearLayout>  
    9.   
    10. </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.   
    17. </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.           
    4.         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Panel);  
    5.           
    6.         mDuration = a.getInteger(R.styleable.Panel_animationDuration, 750);  
    7.         mPosition = a.getInteger(R.styleable.Panel_position, BOTTOM);  
    8.         isAnimation = a.getBoolean(R.styleable.Panel_animationEnable, true);  
    9.         a.recycle();  
    10.           
    11.         //根据mPosition 决定LinearLayout的android:orientation属性  
    12.         mOrientation = (mPosition == TOP || mPosition == BOTTOM)? VERTICAL : HORIZONTAL;  
    13.         setOrientation(mOrientation);  
    14.           
    15.         //初始化mHandle 背景图  
    16.         initialHandlerBg();  
    17.           
    18.     }  

    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.         }  
    8.         else if(mPosition == BOTTOM) {  
    9.             mOpenedHandle = getResources().getDrawable(R.drawable.bottom_switcher_expanded_background);  
    10.             mClosedHandle = getResources().getDrawable(R.drawable.bottom_switcher_collapsed_background);  
    11.           
    12.         }  
    13.         else if(mPosition == LEFT) {  
    14.             mOpenedHandle = getResources().getDrawable(R.drawable.left_switcher_expanded_background);  
    15.             mClosedHandle = getResources().getDrawable(R.drawable.left_switcher_collapsed_background);  
    16.           
    17.         }  
    18.         else if(mPosition == RIGHT) {  
    19.             mOpenedHandle = getResources().getDrawable(R.drawable.right_switcher_expanded_background);  
    20.             mClosedHandle = getResources().getDrawable(R.drawable.right_switcher_collapsed_background);  
    21.           
    22.         }  
    23.     }  

    5. 取出其中的 ViewGroup & Button

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

    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.           
    5.         mContentWidth = mContent.getWidth();  
    6.         mContentHeight = mContent.getHeight();  
    7.           
    8.         paddingTop = this.getPaddingTop();  
    9.         paddingLeft = this.getPaddingLeft();  
    10.     }  

    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.             //置反 即:开-合-开-合-开-...  
    13.             isContentExpand = !isContentExpand;  
    14.         }  
    15.     };  

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

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

    10. 开 即: 打开ViewGroup

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

    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.               
    8.             if(mPosition == TOP){  
    9.                 fromYDelta = -1 * mContentHeight;  
    10.                 toXDelta = 0;  
    11.                   
    12.                 calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight;  
    13.             }  
    14.             else if(mPosition == BOTTOM){  
    15.                 fromYDelta = paddingTop;  
    16.                 toYDelta = fromYDelta + 1 * mContentHeight;  
    17.                   
    18.                 calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight;  
    19.             }  
    20.             else if(mPosition == LEFT){  
    21.                 fromXDelta = -1 * mContentWidth;  
    22.                 toXDelta = 0;  
    23.                   
    24.                 calculatedDuration = mDuration * Math.abs(toXDelta - fromXDelta) / mContentWidth;  
    25.             }  
    26.             else if(mPosition == RIGHT){  
    27.                 fromXDelta = paddingLeft;  
    28.                 toXDelta = fromYDelta + 1 * mContentHeight;  
    29.                   
    30.                 calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight;  
    31.             }  
    32.               
    33.             animation = new TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);  
    34.             animation.setDuration(calculatedDuration);  
    35.             animation.setAnimationListener(aOListener);  
    36.   
    37.             startAnimation(animation);  
    38.         }  
    39.     };  

    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.     }  
    13.     public void doAnimationClose(){  
    14.         post(aClose);  
    15.           
    16.     }  

    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.               
    8.             if(mPosition == TOP){  
    9.                 toYDelta = -1 * mContentHeight;  
    10.                   
    11.                 calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight;  
    12.             }  
    13.             else if(mPosition == BOTTOM){  
    14.                 fromYDelta = 1 *  mContentHeight;  
    15.                 toYDelta = paddingTop;  
    16.                   
    17.                 calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight;  
    18.             }  
    19.             else if(mPosition == LEFT){  
    20.                 toXDelta = -1 * mContentWidth;  
    21.                   
    22.                 calculatedDuration = mDuration * Math.abs(toXDelta - fromXDelta) / mContentWidth;  
    23.             }  
    24.             else if(mPosition == RIGHT){  
    25.                   
    26.             }  
    27.               
    28.             animation = new TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);  
    29.             animation.setDuration(calculatedDuration);  
    30.             animation.setAnimationListener(aCListener);  
    31.               
    32.             startAnimation(animation);  
    33.         }  
    34.     };  

    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.           
    11.         // invoke listener if any  
    12.         if (panelListener != null) {  
    13.             if (isContentExpand) {  
    14.                 panelListener.onPanelOpened(Panel.this);  
    15.             }  
    16.             else {  
    17.                 panelListener.onPanelClosed(Panel.this);  
    18.             }  
    19.         }  
    20.     }  

    15. emulator 运行截图:

    * 先贴其布局

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

    * 运行截图:

     - 开

    - 合

  • 相关阅读:
    apache22与mod_mono
    设计模式之行为型模式
    jquery实现excel导出
    桥本分数式问题的C++算法
    [深入浅出iOS库]之图形库Core Plot
    HDU 1069 Monkey and Banana
    程序员咋学习
    JavaSocket通信(双向,有界面)
    BZOJ 3098(Hash Killer II生日攻击)
    [置顶] iPhone 5S及iWatch或将采用指纹验证技术
  • 原文地址:https://www.cnblogs.com/xingmeng/p/2534869.html
Copyright © 2011-2022 走看看