抽屉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>  

* 运行截图:

 - 开

- 合

原文地址:https://www.cnblogs.com/xingmeng/p/2534869.html