您的位置:首页 > 移动开发 > Android开发

可动态布局的Android抽屉之基础

2011-09-20 10:19 239 查看
本文来自http://blog.csdn.net/hellogv/ ,欢迎转摘,引用必须注明出处!

以前曾经介绍过《Android提高第十九篇之"多方向"抽屉》,当这个抽屉组件不与周围组件发生压挤的情况下(周围组件布局不变),是比较好使的,但是如果需要对周围组件挤压,则用起来欠缺美观了。

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



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



本文实现的抽屉原理是酱紫:

1.抽屉组件主要在屏幕不可视区域,手柄在屏幕边缘的可视区域。即
抽屉.rightMargin=-XXX + 手柄.width

2.指定一个周围组件为可压挤,即LayoutParams.weight=1;当然用户也可以指定多个View.

3.使用AsyncTask来实现弹出/收缩的动画,弹出:抽屉.rightMargin+=XX,收缩:抽屉.rightMargin-=XX

总结,本文的自定义抽屉虽然对压挤周围组件有过渡效果,但是比较耗资源,读者可以针对不同的情况考虑使用。

本文的源码可以到http://download.csdn.net/detail/hellogv/3615686 下载。

接下来贴出本文全部源代码:

main.xml的源码:

view
plainprint?

<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的源码:

view
plainprint?

<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是本文核心,抽屉组件的源码,这个抽屉只实现了从右往左的弹出/从左往右的收缩,读者可以根据自己的需要修改源码来改变抽屉动作的方向:

view
plainprint?

<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);

}

/**Handle的宽度,与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;

/**

* otherView自动布局以适应Panel展开/收缩的空间变化

* @author GV

*

*/

public Panel(Context context,View otherView,int width,int height) {

super(context);

this.mContext=context;

//改变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;//Panel的Container在屏幕不可视区域,Handle在可视区域

mRightMargin=Math.abs(lp.rightMargin);

this.setLayoutParams(lp);

this.setOrientation(LinearLayout.HORIZONTAL);

//设置Handle的属性

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)// CLOSE的状态

new AsynMove().execute(new Integer[] { MOVE_WIDTH });// 正数展开

else if (lp.rightMargin >= 0)// OPEN的状态

new AsynMove().execute(new Integer[] { -MOVE_WIDTH });// 负数收缩

}

});

//btnHandle.setOnTouchListener(HandleTouchEvent);

this.addView(btnHandle);

//设置Container的属性

panelContainer=new LinearLayout(context);

panelContainer.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,

LayoutParams.FILL_PARENT));

this.addView(panelContainer);

}

/**

* 定义收缩时的回调函数

* @param event

*/

public void setPanelClosedEvent(PanelClosedEvent event)

{

this.panelClosedEvent=event;

}

/**

* 定义展开时的回调函数

* @param event

*/

public void setPanelOpenedEvent(PanelOpenedEvent event)

{

this.panelOpenedEvent=event;

}

/**

* 把View放在Panel的Container

* @param v

*/

public void fillPanelContainer(View v)

{

panelContainer.addView(v);

}

/**

* 异步移动Panel

* @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);//调用OPEN回调函数

}

else if(lp.rightMargin==-(mRightMargin) && panelClosedEvent!=null){//收缩之后

panelClosedEvent.onPanelClosed(Panel.this);//调用CLOSE回调函数

}

Panel.this.setLayoutParams(lp);

}

}

}

</span>

main.java是主控部分,演示了Panel的使用:

view
plainprint?

<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);//加入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"));

}

}</span>

后面还会继续介绍如何在Panel加入拖拉效果的处理!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息