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的实现:

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

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/img3"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.topcsa.demo_drawer1.MainActivity$PlaceholderFragment" > <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:text="滑动外面"
android:textSize="18sp" /> <SlidingDrawer
android:id="@+id/slidingdrawer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:content="@+id/content"
android:handle="@+id/handle"
android:orientation="vertical" > <ImageView
android:id="@id/handle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/img1" >
</ImageView> <LinearLayout
android:id="@id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/img2" > <TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="隐藏的内容" />
</LinearLayout>
</SlidingDrawer> </RelativeLayout>

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

 <span style="white-space: pre;">    </span>SlidingDrawer sd = (SlidingDrawer)findViewById(R.id.slidingdrawer);  

         sd.setOnDrawerOpenListener(new OnDrawerOpenListener(){
public void onDrawerOpened() {
// TODO Auto-generated method stub
}
});
sd.setOnDrawerCloseListener(new OnDrawerCloseListener(){
public void onDrawerClosed() {
// TODO Auto-generated method stub
}
});
sd.setOnDrawerScrollListener(new OnDrawerScrollListener(){
public void onScrollEnded() {
// TODO Auto-generated method stub
}
public void onScrollStarted() {
// TODO Auto-generated method stub
}
});

第二种方式DrawerLayout的实现:

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

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".DrawerActivity" > <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" > <!-- The main content view --> <FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" > <Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="open"
/>
</FrameLayout> <!-- The navigation drawer --> <ListView
android:id="@+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#111"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp" />
</android.support.v4.widget.DrawerLayout> </RelativeLayout>

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

 private DrawerLayout mDrawerLayout;

     @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
// 按钮按下,将抽屉打开
mDrawerLayout.openDrawer(Gravity.LEFT); }
}); }

此时,运行代码即可。

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

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

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

main.xml:

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:id="@+id/container">
<GridView android:id="@+id/gridview" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:numColumns="auto_fit"
android:verticalSpacing="10dp" android:gravity="center"
android:columnWidth="50dip" android:horizontalSpacing="10dip" />
</LinearLayout>

item.xml:

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content" android:paddingBottom="4dip"
android:layout_width="fill_parent">
<ImageView android:layout_height="wrap_content" android:id="@+id/ItemImage"
android:layout_width="wrap_content" android:layout_centerHorizontal="true">
</ImageView>
<TextView android:layout_width="wrap_content"
android:layout_below="@+id/ItemImage" android:layout_height="wrap_content"
android:text="TextView01" android:layout_centerHorizontal="true"
android:id="@+id/ItemText">
</TextView>
</RelativeLayout>

在默认Activity中:

 public class main extends Activity {
public Panel panel;
public LinearLayout container;
public GridView gridview;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.setTitle("“可动态布局”的抽屉组件之构建基础-----hellogv");
gridview = (GridView) findViewById(R.id.gridview);
container=(LinearLayout)findViewById(R.id.container);
panel=new Panel(this,gridview,200,LayoutParams.FILL_PARENT);
container.addView(panel);//加入Panel控件 //新建测试组件
TextView tvTest=new TextView(this);
tvTest.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
tvTest.setText("测试组件,红字白底");
tvTest.setTextColor(Color.RED);
tvTest.setBackgroundColor(Color.WHITE);
//加入到Panel里面
panel.fillPanelContainer(tvTest); panel.setPanelClosedEvent(panelClosedEvent);
panel.setPanelOpenedEvent(panelOpenedEvent); //往GridView填充测试数据
ArrayList<HashMap<String, Object>> lstImageItem = new ArrayList<HashMap<String, Object>>();
for (int i = 0; i < 100; i++) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("ItemImage", R.drawable.icon);
map.put("ItemText", "NO." + String.valueOf(i));
lstImageItem.add(map);
} SimpleAdapter saImageItems = new SimpleAdapter(this,
lstImageItem,
R.layout.item,
new String[] { "ItemImage", "ItemText" },
new int[] { R.id.ItemImage, R.id.ItemText });
gridview.setAdapter(saImageItems);
gridview.setOnItemClickListener(new ItemClickListener()); } PanelClosedEvent panelClosedEvent =new PanelClosedEvent(){ @Override
public void onPanelClosed(View panel) {
Log.e("panelClosedEvent","panelClosedEvent");
} }; PanelOpenedEvent panelOpenedEvent =new PanelOpenedEvent(){ @Override
public void onPanelOpened(View panel) {
Log.e("panelOpenedEvent","panelOpenedEvent");
} }; class ItemClickListener implements OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> arg0,View arg1, int arg2, long arg3) {
@SuppressWarnings("unchecked")
HashMap<String, Object> item = (HashMap<String, Object>) arg0
.getItemAtPosition(arg2);
setTitle((String) item.get("ItemText"));
} }
}

新建一个Panel类:

 public class Panel extends LinearLayout implements GestureDetector.OnGestureListener{

     public interface PanelClosedEvent {
void onPanelClosed(View panel);
} public interface PanelOpenedEvent {
void onPanelOpened(View panel);
} private final static int HANDLE_WIDTH=30;
private final static int MOVE_WIDTH=20;
private Button btnHandler;
private LinearLayout panelContainer;
private int mRightMargin=0;
private Context mContext;
private GestureDetector mGestureDetector;
private boolean mIsScrolling=false;
private float mScrollX;
private PanelClosedEvent panelClosedEvent=null;
private PanelOpenedEvent panelOpenedEvent=null; public Panel(Context context,View otherView,int width,int height) {
super(context);
this.mContext=context; //定义手势识别
mGestureDetector = new GestureDetector(mContext,this);
mGestureDetector.setIsLongpressEnabled(false); //改变Panel附近组件的属性
LayoutParams otherLP=(LayoutParams) otherView.getLayoutParams();
otherLP.weight=1;
otherView.setLayoutParams(otherLP); //设置Panel本身的属性
LayoutParams lp=new LayoutParams(width, height);
lp.rightMargin=-lp.width+HANDLE_WIDTH;
mRightMargin=Math.abs(lp.rightMargin);
this.setLayoutParams(lp);
this.setOrientation(LinearLayout.HORIZONTAL); //设置Handler的属性
btnHandler=new Button(context);
btnHandler.setLayoutParams(new LayoutParams(HANDLE_WIDTH,height));
//btnHandler.setOnClickListener(handlerClickEvent);
btnHandler.setOnTouchListener(handlerTouchEvent);
this.addView(btnHandler); //设置Container的属性
panelContainer=new LinearLayout(context);
panelContainer.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
this.addView(panelContainer); } private View.OnTouchListener handlerTouchEvent=new View.OnTouchListener() { @Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_UP &&
mIsScrolling==true)
{
LayoutParams lp=(LayoutParams) Panel.this.getLayoutParams();
if (lp.rightMargin >= (-mRightMargin/2)) {
new AsynMove().execute(new Integer[] { MOVE_WIDTH });
}
else if (lp.rightMargin < (-mRightMargin/2)) {
new AsynMove().execute(new Integer[] { -MOVE_WIDTH });
}
}
return mGestureDetector.onTouchEvent(event);
}
}; /**
*
* @param event
*/
public void setPanelClosedEvent(PanelClosedEvent event)
{
this.panelClosedEvent=event;
} /**
*
* @param event
*/
public void setPanelOpenedEvent(PanelOpenedEvent event)
{
this.panelOpenedEvent=event;
} /**
*
* @param v
*/
public void fillPanelContainer(View v)
{
panelContainer.addView(v);
} /**
*
* @author hellogv
*/
class AsynMove extends AsyncTask<Integer, Integer, Void> { @Override
protected Void doInBackground(Integer... params) {
int times;
if (mRightMargin % Math.abs(params[0]) == 0)
times = mRightMargin / Math.abs(params[0]);
else times = mRightMargin / Math.abs(params[0]) + 1; for (int i = 0; i < times; i++) {
publishProgress(params);
try {
Thread.sleep(Math.abs(params[0]));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
} @Override
protected void onProgressUpdate(Integer... params) {
LayoutParams lp = (LayoutParams) Panel.this.getLayoutParams();
if (params[0] < 0)
lp.rightMargin = Math.max(lp.rightMargin + params[0],
(-mRightMargin));
else
lp.rightMargin = Math.min(lp.rightMargin + params[0], 0); if(lp.rightMargin==0 && panelOpenedEvent!=null){
panelOpenedEvent.onPanelOpened(Panel.this);
}
else if(lp.rightMargin==-(mRightMargin) && panelClosedEvent!=null){
panelClosedEvent.onPanelClosed(Panel.this);
}
Panel.this.setLayoutParams(lp);
}
} @Override
public boolean onDown(MotionEvent e) {
mScrollX=0;
mIsScrolling=false;
return false;
} @Override
public boolean onSingleTapUp(MotionEvent e) {
LayoutParams lp = (LayoutParams) Panel.this.getLayoutParams();
if (lp.rightMargin < 0)
new AsynMove().execute(new Integer[] { MOVE_WIDTH });
else if (lp.rightMargin >= 0)
new AsynMove().execute(new Integer[] { -MOVE_WIDTH });
return false;
} @Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
mIsScrolling=true;
mScrollX+=distanceX; LayoutParams lp=(LayoutParams) Panel.this.getLayoutParams();
if (lp.rightMargin < -1 && mScrollX > 0) {
lp.rightMargin = Math.min((lp.rightMargin + (int) mScrollX),0);
Panel.this.setLayoutParams(lp);
Log.e("onScroll",lp.rightMargin+"");
}
else if (lp.rightMargin > -(mRightMargin) && mScrollX < 0) {
lp.rightMargin = Math.max((lp.rightMargin + (int) mScrollX),-mRightMargin);
Panel.this.setLayoutParams(lp);
} if(lp.rightMargin==0 && panelOpenedEvent!=null){
panelOpenedEvent.onPanelOpened(Panel.this);
}
else if(lp.rightMargin==-(mRightMargin) && panelClosedEvent!=null){
panelClosedEvent.onPanelClosed(Panel.this);
}
Log.e("onScroll",lp.rightMargin+""); return false;
} @Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {return false;}
@Override
public void onLongPress(MotionEvent e) {}
@Override
public void onShowPress(MotionEvent e) {} }

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

上一篇:android抽屉效果


下一篇:BizTalk开发系列(七) Hello World2