昨天在用“酷我音乐”听歌的时候注意到了界面右上角的四角方块,当我点击这个方块的时候会从屏幕的左边弹出新的界面而把原来的界面挤到左边,是显示了一小部分。
于是,我便在网上查询了一下相关的文章,现将这种效果收集了一下,由于文章太多太杂(有CSDN、博客园、开源中国等)我就不具体指明了。如有侵权敬请谅解。
要实现抽屉效果,有两种方式:
- 使用大家熟知的滑动抽屉类SlidingDrawer。http://developer.android.com/reference/android/widget/SlidingDrawer.html
- 使用DrawerLayout。http://developer.android.com/reference/android/support/v4/widget/DrawerLayout.html
下面我们分别用这两种方式来实现这个效果:
第一种方式SlidingDrawer的实现:
仅需要实现布局文件就能看到简单的效果:
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>
此时运行程序就可以看到简单的抽屉效果,此外SlidingDrawer还提供了一些方法:
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 });
第二种方式DrawerLayout的实现:
我们首先还是来实现布局文件main.xml:
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>
然后我们修改MainActivity中的代码:
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 }
此时,运行代码即可。
大家需要在“抽屉”中放些什么东西,自己在布局文件和java代码中添加或修改就行了。
此外,我再附加些抽屉效果,个人感觉还不错:
两个布局文件main.xml和item.xml分别为:
main.xml:
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>
item.xml:
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>
在默认Activity中:
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 }
新建一个Panel类:
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 }
此时就可以运行这个例子了。