?
本文来自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的源码:
- <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);??
- ????}??
- ????/**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展开/收缩的空间变化?
- [email protected]?
- ?????*?
- ?????*/???
- ????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);??
- ????}??
- ??
- ????/**?
- ?????*?定义收缩时的回调函数?
- [email protected]?
- ?????*/??
- ????public?void?setPanelClosedEvent(PanelClosedEvent?event)??
- ????{??
- ????????this.panelClosedEvent=event;??
- ????}??
- ??????
- ????/**?
- ?????*?定义展开时的回调函数?
- [email protected]?
- ?????*/??
- ????public?void?setPanelOpenedEvent(PanelOpenedEvent?event)??
- ????{??
- ????????this.panelOpenedEvent=event;??
- ????}??
- ??????
- ????/**?
- ?????*?把View放在Panel的Container?
- [email protected]?
- ?????*/??
- ????public?void?fillPanelContainer(View?v)??
- ????{??
- ????????panelContainer.addView(v);??
- ????}??
- ??????
- ????/**?
- ?????*?异步移动Panel?
- [email protected]?
- ?????*/??
- ????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的使用:
- <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加入拖拉效果的处理!