Android 抽屉效果

昨天在用“酷我音乐”听歌的时候注意到了界面右上角的四角方块,当我点击这个方块的时候会从屏幕的左边弹出新的界面而把原来的界面挤到左边,是显示了一小部分。

于是,我便在网上查询了一下相关的文章,现将这种效果收集了一下,由于文章太多太杂(有CSDN、博客园、开源中国等)我就不具体指明了。如有侵权敬请谅解。

 

要实现抽屉效果,有两种方式:

  1. 使用大家熟知的滑动抽屉类SlidingDrawer。http://developer.android.com/reference/android/widget/SlidingDrawer.html
  2. 使用DrawerLayout。http://developer.android.com/reference/android/support/v4/widget/DrawerLayout.html

下面我们分别用这两种方式来实现这个效果:

第一种方式SlidingDrawer的实现:

仅需要实现布局文件就能看到简单的效果:

Android 抽屉效果
 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:background="@drawable/img3"
 6     android:paddingBottom="@dimen/activity_vertical_margin"
 7     android:paddingLeft="@dimen/activity_horizontal_margin"
 8     android:paddingRight="@dimen/activity_horizontal_margin"
 9     android:paddingTop="@dimen/activity_vertical_margin"
10     tools:context="com.topcsa.demo_drawer1.MainActivity$PlaceholderFragment" >
11 
12     <TextView
13         android:layout_width="match_parent"
14         android:layout_height="wrap_content"
15         android:gravity="center_vertical|center_horizontal"
16         android:text="滑动外面"
17         android:textSize="18sp" />
18 
19     <SlidingDrawer
20         android:id="@+id/slidingdrawer"
21         android:layout_width="match_parent"
22         android:layout_height="wrap_content"
23         android:content="@+id/content"
24         android:handle="@+id/handle"
25         android:orientation="vertical" >
26 
27         <ImageView
28             android:id="@id/handle"
29             android:layout_width="wrap_content"
30             android:layout_height="wrap_content"
31             android:src="@drawable/img1" >
32         </ImageView>
33 
34         <LinearLayout
35             android:id="@id/content"
36             android:layout_width="match_parent"
37             android:layout_height="match_parent"
38             android:background="@drawable/img2" >
39 
40             <TextView
41                 android:layout_width="match_parent"
42                 android:layout_height="match_parent"
43                 android:text="隐藏的内容" />
44         </LinearLayout>
45     </SlidingDrawer>
46 
47 </RelativeLayout>
View Code

此时运行程序就可以看到简单的抽屉效果,此外SlidingDrawer还提供了一些方法:

Android 抽屉效果
 1 <span style="white-space: pre;">    </span>SlidingDrawer sd = (SlidingDrawer)findViewById(R.id.slidingdrawer);  
 2           
 3         sd.setOnDrawerOpenListener(new OnDrawerOpenListener(){  
 4             public void onDrawerOpened() {  
 5                 // TODO Auto-generated method stub  
 6             }  
 7         });  
 8         sd.setOnDrawerCloseListener(new OnDrawerCloseListener(){  
 9             public void onDrawerClosed() {  
10                 // TODO Auto-generated method stub  
11             }  
12         });  
13         sd.setOnDrawerScrollListener(new OnDrawerScrollListener(){  
14             public void onScrollEnded() {  
15                 // TODO Auto-generated method stub  
16             }  
17             public void onScrollStarted() {  
18                 // TODO Auto-generated method stub  
19             }     
20         });
View Code

 

第二种方式DrawerLayout的实现:

我们首先还是来实现布局文件main.xml:

Android 抽屉效果
 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:paddingBottom="@dimen/activity_vertical_margin"
 6     android:paddingLeft="@dimen/activity_horizontal_margin"
 7     android:paddingRight="@dimen/activity_horizontal_margin"
 8     android:paddingTop="@dimen/activity_vertical_margin"
 9     tools:context=".DrawerActivity" >
10 
11     <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
12         android:id="@+id/drawer_layout"
13         android:layout_width="match_parent"
14         android:layout_height="match_parent" >
15 
16         <!-- The main content view -->
17 
18         <FrameLayout
19             android:id="@+id/content_frame"
20             android:layout_width="match_parent"
21             android:layout_height="match_parent" >
22 
23             <Button
24                 android:id="@+id/btn"
25                 android:layout_width="match_parent"
26                 android:layout_height="wrap_content"
27                 android:text="open" 
28                 />
29         </FrameLayout>
30 
31         <!-- The navigation drawer -->
32         
33         <ListView
34             android:id="@+id/left_drawer"
35             android:layout_width="240dp"
36             android:layout_height="match_parent"
37             android:layout_gravity="start"
38             android:background="#111"
39             android:choiceMode="singleChoice"
40             android:divider="@android:color/transparent"
41             android:dividerHeight="0dp" />
42     </android.support.v4.widget.DrawerLayout>
43 
44 </RelativeLayout>
View Code

然后我们修改MainActivity中的代码:

Android 抽屉效果
 1 private DrawerLayout mDrawerLayout;
 2 
 3     @Override
 4     protected void onCreate(Bundle savedInstanceState) {
 5         super.onCreate(savedInstanceState);
 6         setContentView(R.layout.main);
 7         mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
 8 
 9         Button button = (Button) findViewById(R.id.btn);
10         button.setOnClickListener(new OnClickListener() {
11 
12             @Override
13             public void onClick(View v) {
14                 // 按钮按下,将抽屉打开
15                 mDrawerLayout.openDrawer(Gravity.LEFT);
16 
17             }
18         });
19 
20     }
View Code

此时,运行代码即可。

大家需要在“抽屉”中放些什么东西,自己在布局文件和java代码中添加或修改就行了。

 

此外,我再附加些抽屉效果,个人感觉还不错:

两个布局文件main.xml和item.xml分别为:

main.xml:

Android 抽屉效果
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3     android:layout_width="fill_parent" android:layout_height="fill_parent"
4     android:id="@+id/container">
5     <GridView android:id="@+id/gridview" android:layout_width="fill_parent"
6         android:layout_height="fill_parent" android:numColumns="auto_fit"
7         android:verticalSpacing="10dp" android:gravity="center"
8         android:columnWidth="50dip" android:horizontalSpacing="10dip" />
9 </LinearLayout>
View Code

item.xml:

Android 抽屉效果
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_height="wrap_content" android:paddingBottom="4dip"
 4     android:layout_width="fill_parent">
 5     <ImageView android:layout_height="wrap_content" android:id="@+id/ItemImage"
 6         android:layout_width="wrap_content" android:layout_centerHorizontal="true">
 7     </ImageView>
 8     <TextView android:layout_width="wrap_content"
 9         android:layout_below="@+id/ItemImage" android:layout_height="wrap_content"
10         android:text="TextView01" android:layout_centerHorizontal="true"
11         android:id="@+id/ItemText">
12     </TextView>
13 </RelativeLayout>  
View Code

在默认Activity中:

Android 抽屉效果
 1 public class main extends Activity {
 2     public Panel panel;  
 3     public LinearLayout container;  
 4     public GridView gridview;  
 5     public void onCreate(Bundle savedInstanceState) {  
 6         super.onCreate(savedInstanceState);  
 7         setContentView(R.layout.main);  
 8         this.setTitle("“可动态布局”的抽屉组件之构建基础-----hellogv");  
 9         gridview = (GridView) findViewById(R.id.gridview);  
10         container=(LinearLayout)findViewById(R.id.container);  
11         panel=new Panel(this,gridview,200,LayoutParams.FILL_PARENT);  
12         container.addView(panel);//加入Panel控件  
13           
14         //新建测试组件  
15         TextView tvTest=new TextView(this);  
16         tvTest.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));  
17         tvTest.setText("测试组件,红字白底");  
18         tvTest.setTextColor(Color.RED);  
19         tvTest.setBackgroundColor(Color.WHITE);  
20         //加入到Panel里面  
21         panel.fillPanelContainer(tvTest);  
22           
23         panel.setPanelClosedEvent(panelClosedEvent);  
24         panel.setPanelOpenedEvent(panelOpenedEvent);  
25           
26         //往GridView填充测试数据  
27         ArrayList<HashMap<String, Object>> lstImageItem = new ArrayList<HashMap<String, Object>>();  
28         for (int i = 0; i < 100; i++) {  
29             HashMap<String, Object> map = new HashMap<String, Object>();  
30             map.put("ItemImage", R.drawable.icon);  
31             map.put("ItemText", "NO." + String.valueOf(i));  
32             lstImageItem.add(map);  
33         }  
34   
35         SimpleAdapter saImageItems = new SimpleAdapter(this,   
36                 lstImageItem,  
37                 R.layout.item,   
38                 new String[] { "ItemImage", "ItemText" },  
39                 new int[] { R.id.ItemImage, R.id.ItemText });  
40         gridview.setAdapter(saImageItems);  
41         gridview.setOnItemClickListener(new ItemClickListener());  
42           
43     }  
44   
45     PanelClosedEvent panelClosedEvent =new PanelClosedEvent(){  
46   
47         @Override  
48         public void onPanelClosed(View panel) {  
49             Log.e("panelClosedEvent","panelClosedEvent");  
50         }  
51           
52     };  
53       
54     PanelOpenedEvent panelOpenedEvent =new PanelOpenedEvent(){  
55   
56         @Override  
57         public void onPanelOpened(View panel) {  
58             Log.e("panelOpenedEvent","panelOpenedEvent");  
59         }  
60           
61     };  
62       
63     class ItemClickListener implements OnItemClickListener {  
64         @Override  
65         public void onItemClick(AdapterView<?> arg0,View arg1, int arg2, long arg3) {  
66             @SuppressWarnings("unchecked")  
67             HashMap<String, Object> item = (HashMap<String, Object>) arg0  
68                     .getItemAtPosition(arg2);  
69             setTitle((String) item.get("ItemText"));  
70         }  
71   
72     }
73 }
View Code

新建一个Panel类:

Android 抽屉效果
  1 public class Panel extends LinearLayout implements GestureDetector.OnGestureListener{
  2     
  3     public interface PanelClosedEvent {
  4         void onPanelClosed(View panel);
  5     }
  6     
  7     public interface PanelOpenedEvent {
  8         void onPanelOpened(View panel);
  9     }
 10     
 11     private final static int HANDLE_WIDTH=30;
 12     private final static int MOVE_WIDTH=20;
 13     private Button btnHandler;
 14     private LinearLayout panelContainer;
 15     private int mRightMargin=0;
 16     private Context mContext;
 17     private GestureDetector mGestureDetector;
 18     private boolean mIsScrolling=false;
 19     private float mScrollX;
 20     private PanelClosedEvent panelClosedEvent=null;
 21     private PanelOpenedEvent panelOpenedEvent=null;
 22     
 23     public Panel(Context context,View otherView,int width,int height) {
 24         super(context);
 25         this.mContext=context;
 26         
 27         //定义手势识别 
 28         mGestureDetector = new GestureDetector(mContext,this);
 29         mGestureDetector.setIsLongpressEnabled(false);
 30         
 31         //改变Panel附近组件的属性
 32         LayoutParams otherLP=(LayoutParams) otherView.getLayoutParams();
 33         otherLP.weight=1;
 34         otherView.setLayoutParams(otherLP);
 35         
 36         //设置Panel本身的属性 
 37         LayoutParams lp=new LayoutParams(width, height);
 38         lp.rightMargin=-lp.width+HANDLE_WIDTH;
 39         mRightMargin=Math.abs(lp.rightMargin);
 40         this.setLayoutParams(lp);
 41         this.setOrientation(LinearLayout.HORIZONTAL);
 42         
 43         //设置Handler的属性  
 44         btnHandler=new Button(context);
 45         btnHandler.setLayoutParams(new LayoutParams(HANDLE_WIDTH,height));
 46         //btnHandler.setOnClickListener(handlerClickEvent);
 47         btnHandler.setOnTouchListener(handlerTouchEvent);
 48         this.addView(btnHandler);
 49         
 50         //设置Container的属性  
 51         panelContainer=new LinearLayout(context);
 52         panelContainer.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
 53                 LayoutParams.FILL_PARENT));
 54         this.addView(panelContainer);
 55 
 56     }
 57 
 58     private View.OnTouchListener handlerTouchEvent=new View.OnTouchListener() {
 59         
 60         @Override
 61         public boolean onTouch(View v, MotionEvent event) {
 62             if(event.getAction()==MotionEvent.ACTION_UP && 
 63                     mIsScrolling==true)
 64             {
 65                 LayoutParams lp=(LayoutParams) Panel.this.getLayoutParams();
 66                 if (lp.rightMargin >= (-mRightMargin/2)) {
 67                     new AsynMove().execute(new Integer[] { MOVE_WIDTH });
 68                 } 
 69                 else if (lp.rightMargin < (-mRightMargin/2)) {
 70                     new AsynMove().execute(new Integer[] { -MOVE_WIDTH });
 71                 }
 72             }
 73             return mGestureDetector.onTouchEvent(event); 
 74         }
 75     };
 76 
 77     /**
 78      * 
 79      * @param event
 80      */
 81     public void setPanelClosedEvent(PanelClosedEvent event)
 82     {
 83         this.panelClosedEvent=event;
 84     }
 85     
 86     /**
 87      * 
 88      * @param event
 89      */
 90     public void setPanelOpenedEvent(PanelOpenedEvent event)
 91     {
 92         this.panelOpenedEvent=event;
 93     }
 94     
 95     /**
 96      * 
 97      * @param v
 98      */
 99     public void fillPanelContainer(View v)
100     {
101         panelContainer.addView(v);
102     }
103     
104     /**
105      * 
106      * @author hellogv 
107      */
108     class AsynMove extends AsyncTask<Integer, Integer, Void> {
109 
110         @Override
111         protected Void doInBackground(Integer... params) {
112             int times;
113             if (mRightMargin % Math.abs(params[0]) == 0)
114                 times = mRightMargin / Math.abs(params[0]);
115             else
116                 
117                 times = mRightMargin / Math.abs(params[0]) + 1;
118 
119             for (int i = 0; i < times; i++) {
120                 publishProgress(params);
121                 try {
122                     Thread.sleep(Math.abs(params[0]));
123                 } catch (InterruptedException e) {
124                     // TODO Auto-generated catch block
125                     e.printStackTrace();
126                 }
127             }
128             return null;
129         }
130 
131         @Override
132         protected void onProgressUpdate(Integer... params) {
133             LayoutParams lp = (LayoutParams) Panel.this.getLayoutParams();
134             if (params[0] < 0)
135                 lp.rightMargin = Math.max(lp.rightMargin + params[0],
136                         (-mRightMargin));
137             else
138                 lp.rightMargin = Math.min(lp.rightMargin + params[0], 0);
139 
140             if(lp.rightMargin==0 && panelOpenedEvent!=null){
141                 panelOpenedEvent.onPanelOpened(Panel.this);
142             }
143             else if(lp.rightMargin==-(mRightMargin) && panelClosedEvent!=null){
144                 panelClosedEvent.onPanelClosed(Panel.this);
145             }
146             Panel.this.setLayoutParams(lp);
147         }
148     }
149 
150     @Override
151     public boolean onDown(MotionEvent e) {
152         mScrollX=0;
153         mIsScrolling=false;
154         return false;
155     }
156 
157     @Override
158     public boolean onSingleTapUp(MotionEvent e) {
159         LayoutParams lp = (LayoutParams) Panel.this.getLayoutParams();
160         if (lp.rightMargin < 0)
161             new AsynMove().execute(new Integer[] { MOVE_WIDTH });
162         else if (lp.rightMargin >= 0)
163             new AsynMove().execute(new Integer[] { -MOVE_WIDTH });
164         return false;
165     }
166     
167     @Override
168     public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
169             float distanceY) {
170         mIsScrolling=true;
171         mScrollX+=distanceX;
172         
173         LayoutParams lp=(LayoutParams) Panel.this.getLayoutParams();
174         if (lp.rightMargin < -1 && mScrollX > 0) {
175             lp.rightMargin = Math.min((lp.rightMargin + (int) mScrollX),0);
176             Panel.this.setLayoutParams(lp);
177             Log.e("onScroll",lp.rightMargin+"");
178         } 
179         else if (lp.rightMargin > -(mRightMargin) && mScrollX < 0) {
180             lp.rightMargin = Math.max((lp.rightMargin + (int) mScrollX),-mRightMargin);
181             Panel.this.setLayoutParams(lp);
182         }
183         
184         if(lp.rightMargin==0 && panelOpenedEvent!=null){
185             panelOpenedEvent.onPanelOpened(Panel.this);
186         }
187         else if(lp.rightMargin==-(mRightMargin) && panelClosedEvent!=null){
188             panelClosedEvent.onPanelClosed(Panel.this);
189         }
190         Log.e("onScroll",lp.rightMargin+"");
191         
192         return false;
193     }
194     
195     @Override
196     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
197             float velocityY) {return false;}
198     @Override
199     public void onLongPress(MotionEvent e) {}
200     @Override
201     public void onShowPress(MotionEvent e) {}
202 
203 }
View Code

此时就可以运行这个例子了。

Android 抽屉效果,布布扣,bubuko.com

Android 抽屉效果

上一篇:A Mathematical Curiosity


下一篇:Android横竖屏切换和灭屏亮屏时Activity的生命周期探究(1)