如下图。在对周围压挤的情况下,抽屉是先把周围的组件一次性压挤,再通过动画效果展开/收缩的,这种做法的好处是快速简单,坏处是如果挤压范围过大,则效果生硬。

本文实现的自定义抽屉组件,主要针对这种压挤效果做出改良,渐进式压挤周围组件,使得过渡效果更加美观。如下图。

本文实现的抽屉原理是酱紫:
1.抽屉组件主要在屏幕不可视区域,手柄在屏幕边缘的可视区域。即 抽屉.rightMargin=-XXX + 手柄.width
2.指定一个周围组件为可压挤,即LayoutParams.weight=1;当然用户也可以指定多个View.
3.使用AsyncTask来实现弹出/收缩的动画,弹出:抽屉.rightMargin+=XX,收缩:抽屉.rightMargin-=XX
总结,本文的自定义抽屉虽然对压挤周围组件有过渡效果,但是比较耗资源,读者可以针对不同的情况考虑使用。
本文的源码可以到http://download.csdn.net/detail/hellogv/3615686 下载。
接下来贴出本文全部源代码:
main.xml的源码:
-
<span style="font-family:Comic Sans MS;font-size:18px;"><?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></span>
GridView的Item.xml的源码:
-
<span style="font-family:Comic Sans MS;font-size:18px;"><?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> </span>
Panel.java是本文核心,抽屉组件的源码,这个抽屉只实现了从右往左的弹出/从左往右的收缩,读者可以根据自己的需要修改源码来改变抽屉动作的方向:
-
<span style="font-family:Comic Sans MS;font-size:18px;">public class Panel extends LinearLayout{
-
-
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 btnHandle;
-
private LinearLayout panelContainer;
-
private int mRightMargin=0;
-
private Context mContext;
-
private PanelClosedEvent panelClosedEvent=null;
-
private PanelOpenedEvent panelOpenedEvent=null;
-
-
-
-
-
-
-
public Panel(Context context,View otherView,int width,int height) {
-
super(context);
-
this.mContext=context;
-
-
-
LayoutParams otherLP=(LayoutParams) otherView.getLayoutParams();
-
otherLP.weight=1;
-
otherView.setLayoutParams(otherLP);
-
-
-
LayoutParams lp=new LayoutParams(width, height);
-
lp.rightMargin=-lp.width+HANDLE_WIDTH;
-
mRightMargin=Math.abs(lp.rightMargin);
-
this.setLayoutParams(lp);
-
this.setOrientation(LinearLayout.HORIZONTAL);
-
-
-
btnHandle=new Button(context);
-
btnHandle.setLayoutParams(new LayoutParams(HANDLE_WIDTH,height));
-
btnHandle.setOnClickListener(new OnClickListener(){
-
-
@Override
-
public void onClick(View arg0) {
-
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 });
-
}
-
-
});
-
-
this.addView(btnHandle);
-
-
-
panelContainer=new LinearLayout(context);
-
panelContainer.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
-
LayoutParams.FILL_PARENT));
-
this.addView(panelContainer);
-
}
-
-
-
-
-
-
public void setPanelClosedEvent(PanelClosedEvent event)
-
{
-
this.panelClosedEvent=event;
-
}
-
-
-
-
-
-
public void setPanelOpenedEvent(PanelOpenedEvent event)
-
{
-
this.panelOpenedEvent=event;
-
}
-
-
-
-
-
-
public void fillPanelContainer(View v)
-
{
-
panelContainer.addView(v);
-
}
-
-
-
-
-
-
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) {
-
-
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);
-
}
-
}
-
-
}
-
</span>
main.java是主控部分,演示了Panel的使用:
-
<span style="font-family:Comic Sans MS;font-size:18px;">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);
-
-
-
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.fillPanelContainer(tvTest);
-
-
panel.setPanelClosedEvent(panelClosedEvent);
-
panel.setPanelOpenedEvent(panelOpenedEvent);
-
-
-
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"));
-
}
-
-
}</span>
可动态布局的Android抽屉之基础 分类: Android番外
原文:http://blog.csdn.net/lsong89/article/details/18866299