http://blog.csdn.net/hellogv/article/details/6789698

http://blog.csdn.net/hellogv/article/details/6789698

http://blog.csdn.net/hellogv/article/details/6789698http://blog.csdn.net/hellogv/article/details/6789698

http://blog.csdn.net/hellogv/article/details/6789698

http://blog.csdn.net/hellogv/article/details/6789698

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

分类:Android番外 35650人阅读 评论(40) 收藏 举报 android layout integer object encoding interface

本文来自http://blog.csdn.net/hellogv/,欢迎转摘,引用必须注明出处!

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

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

可动态布局的Android抽屉之基础_第1张图片

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

可动态布局的Android抽屉之基础_第2张图片

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

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

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

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

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

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

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

main.xml的源码:

[html] view plain copy print ?
  1. <spanstyle="font-family:ComicSansMS;font-size:18px;"><?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns: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. <GridViewandroid: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></span>

GridView的Item.xml的源码:

[html] view plain copy print ?
  1. <spanstyle="font-family:ComicSansMS;font-size:18px;"><?xmlversion="1.0"encoding="utf-8"?>
  2. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_height="wrap_content"android:paddingBottom="4dip"
  4. android:layout_width="fill_parent">
  5. <ImageViewandroid:layout_height="wrap_content"android:id="@+id/ItemImage"
  6. android:layout_width="wrap_content"android:layout_centerHorizontal="true">
  7. </ImageView>
  8. <TextViewandroid: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></span>

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

[java] view plain copy print ?
  1. <spanstyle="font-family:ComicSansMS;font-size:18px;">publicclassPanelextendsLinearLayout{
  2. publicinterfacePanelClosedEvent{
  3. voidonPanelClosed(Viewpanel);
  4. }
  5. publicinterfacePanelOpenedEvent{
  6. voidonPanelOpened(Viewpanel);
  7. }
  8. /**Handle的宽度,与Panel等高*/
  9. privatefinalstaticintHANDLE_WIDTH=30;
  10. /**每次自动展开/收缩的范围*/
  11. privatefinalstaticintMOVE_WIDTH=20;
  12. privateButtonbtnHandle;
  13. privateLinearLayoutpanelContainer;
  14. privateintmRightMargin=0;
  15. privateContextmContext;
  16. privatePanelClosedEventpanelClosedEvent=null;
  17. privatePanelOpenedEventpanelOpenedEvent=null;
  18. /**
  19. *otherView自动布局以适应Panel展开/收缩的空间变化
  20. *@authorGV
  21. *
  22. */
  23. publicPanel(Contextcontext,ViewotherView,intwidth,intheight){
  24. super(context);
  25. this.mContext=context;
  26. //改变Panel附近组件的属性
  27. LayoutParamsotherLP=(LayoutParams)otherView.getLayoutParams();
  28. otherLP.weight=1;//支持压挤
  29. otherView.setLayoutParams(otherLP);
  30. //设置Panel本身的属性
  31. LayoutParamslp=newLayoutParams(width,height);
  32. lp.rightMargin=-lp.width+HANDLE_WIDTH;//Panel的Container在屏幕不可视区域,Handle在可视区域
  33. mRightMargin=Math.abs(lp.rightMargin);
  34. this.setLayoutParams(lp);
  35. this.setOrientation(LinearLayout.HORIZONTAL);
  36. //设置Handle的属性
  37. btnHandle=newButton(context);
  38. btnHandle.setLayoutParams(newLayoutParams(HANDLE_WIDTH,height));
  39. btnHandle.setOnClickListener(newOnClickListener(){
  40. @Override
  41. publicvoidonClick(Viewarg0){
  42. LayoutParamslp=(LayoutParams)Panel.this.getLayoutParams();
  43. if(lp.rightMargin<0)//CLOSE的状态
  44. newAsynMove().execute(newInteger[]{MOVE_WIDTH});//正数展开
  45. elseif(lp.rightMargin>=0)//OPEN的状态
  46. newAsynMove().execute(newInteger[]{-MOVE_WIDTH});//负数收缩
  47. }
  48. });
  49. //btnHandle.setOnTouchListener(HandleTouchEvent);
  50. this.addView(btnHandle);
  51. //设置Container的属性
  52. panelContainer=newLinearLayout(context);
  53. panelContainer.setLayoutParams(newLayoutParams(LayoutParams.FILL_PARENT,
  54. LayoutParams.FILL_PARENT));
  55. this.addView(panelContainer);
  56. }
  57. /**
  58. *定义收缩时的回调函数
  59. *@paramevent
  60. */
  61. publicvoidsetPanelClosedEvent(PanelClosedEventevent)
  62. {
  63. this.panelClosedEvent=event;
  64. }
  65. /**
  66. *定义展开时的回调函数
  67. *@paramevent
  68. */
  69. publicvoidsetPanelOpenedEvent(PanelOpenedEventevent)
  70. {
  71. this.panelOpenedEvent=event;
  72. }
  73. /**
  74. *把View放在Panel的Container
  75. *@paramv
  76. */
  77. publicvoidfillPanelContainer(Viewv)
  78. {
  79. panelContainer.addView(v);
  80. }
  81. /**
  82. *异步移动Panel
  83. *@authorhellogv
  84. */
  85. classAsynMoveextendsAsyncTask<Integer,Integer,Void>{
  86. @Override
  87. protectedVoiddoInBackground(Integer...params){
  88. inttimes;
  89. if(mRightMargin%Math.abs(params[0])==0)//整除
  90. times=mRightMargin/Math.abs(params[0]);
  91. else
  92. //有余数
  93. times=mRightMargin/Math.abs(params[0])+1;
  94. for(inti=0;i<times;i++){
  95. publishProgress(params);
  96. try{
  97. Thread.sleep(Math.abs(params[0]));
  98. }catch(InterruptedExceptione){
  99. //TODOAuto-generatedcatchblock
  100. e.printStackTrace();
  101. }
  102. }
  103. returnnull;
  104. }
  105. @Override
  106. protectedvoidonProgressUpdate(Integer...params){
  107. LayoutParamslp=(LayoutParams)Panel.this.getLayoutParams();
  108. if(params[0]<0)
  109. lp.rightMargin=Math.max(lp.rightMargin+params[0],
  110. (-mRightMargin));
  111. else
  112. lp.rightMargin=Math.min(lp.rightMargin+params[0],0);
  113. if(lp.rightMargin==0&&panelOpenedEvent!=null){//展开之后
  114. panelOpenedEvent.onPanelOpened(Panel.this);//调用OPEN回调函数
  115. }
  116. elseif(lp.rightMargin==-(mRightMargin)&&panelClosedEvent!=null){//收缩之后
  117. panelClosedEvent.onPanelClosed(Panel.this);//调用CLOSE回调函数
  118. }
  119. Panel.this.setLayoutParams(lp);
  120. }
  121. }
  122. }
  123. </span>

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

[java] view plain copy print ?
  1. <spanstyle="font-family:ComicSansMS;font-size:18px;">publicclassmainextendsActivity{
  2. publicPanelpanel;
  3. publicLinearLayoutcontainer;
  4. publicGridViewgridview;
  5. publicvoidonCreate(BundlesavedInstanceState){
  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=newPanel(this,gridview,200,LayoutParams.FILL_PARENT);
  12. container.addView(panel);//加入Panel控件
  13. //新建测试组件
  14. TextViewtvTest=newTextView(this);
  15. tvTest.setLayoutParams(newLayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
  16. tvTest.setText("测试组件,红字白底");
  17. tvTest.setTextColor(Color.RED);
  18. tvTest.setBackgroundColor(Color.WHITE);
  19. //加入到Panel里面
  20. panel.fillPanelContainer(tvTest);
  21. panel.setPanelClosedEvent(panelClosedEvent);
  22. panel.setPanelOpenedEvent(panelOpenedEvent);
  23. //往GridView填充测试数据
  24. ArrayList<HashMap<String,Object>>lstImageItem=newArrayList<HashMap<String,Object>>();
  25. for(inti=0;i<100;i++){
  26. HashMap<String,Object>map=newHashMap<String,Object>();
  27. map.put("ItemImage",R.drawable.icon);
  28. map.put("ItemText","NO."+String.valueOf(i));
  29. lstImageItem.add(map);
  30. }
  31. SimpleAdaptersaImageItems=newSimpleAdapter(this,
  32. lstImageItem,
  33. R.layout.item,
  34. newString[]{"ItemImage","ItemText"},
  35. newint[]{R.id.ItemImage,R.id.ItemText});
  36. gridview.setAdapter(saImageItems);
  37. gridview.setOnItemClickListener(newItemClickListener());
  38. }
  39. PanelClosedEventpanelClosedEvent=newPanelClosedEvent(){
  40. @Override
  41. publicvoidonPanelClosed(Viewpanel){
  42. Log.e("panelClosedEvent","panelClosedEvent");
  43. }
  44. };
  45. PanelOpenedEventpanelOpenedEvent=newPanelOpenedEvent(){
  46. @Override
  47. publicvoidonPanelOpened(Viewpanel){
  48. Log.e("panelOpenedEvent","panelOpenedEvent");
  49. }
  50. };
  51. classItemClickListenerimplementsOnItemClickListener{
  52. @Override
  53. publicvoidonItemClick(AdapterView<?>arg0,Viewarg1,intarg2,longarg3){
  54. @SuppressWarnings("unchecked")
  55. HashMap<String,Object>item=(HashMap<String,Object>)arg0
  56. .getItemAtPosition(arg2);
  57. setTitle((String)item.get("ItemText"));
  58. }
  59. }</span>

后面还会继续介绍如何在Panel加入拖拉效果的处理!


















http://blog.csdn.net/hellogv/article/details/6264706

http://blog.csdn.net/hellogv/article/details/6264706

http://blog.csdn.net/hellogv/article/details/6264706


Android提高第十九篇之"多方向"抽屉

分类:Android提高 42640人阅读 评论(135) 收藏 举报 android action up google float 扩展

本文来自http://blog.csdn.net/hellogv/,引用必须注明出处!

在android上要实现类似Launch的抽屉效果,大家一定首先会想起SlidingDrawer。SlidingDrawer是android官方控件之一,本文的主角不是它,而是民间的控件工具集合~~~android-misc-widgets。android-misc-widgets里面包含几个widget:Panel、SmoothButton、Switcher、VirtualKeyboard,还有一些动画特效,本文主要介绍抽屉容器Panel的用法。android-misc-widgets的google工程地址:-widgets/http://code.google.com/p/android-misc,工程代码中Panel的演示效果如下:

可动态布局的Android抽屉之基础_第3张图片

这个Panel控件可以轻易实现不同方向的抽屉效果,比SlidingDrawer有更强的扩展性!

在多次使用Panel的过程中,发现Panel有个bug,会间断性出现“闪烁”,也就是在onTouchListener里面的触发ACTION_DOWN后,抽屉瞬间弹出然后瞬间回收(版本日期为Feb 3, 2009)。把原Panel的OnTouchListener,即以下代码:

[java] view plain copy
  1. OnTouchListenertouchListener=newOnTouchListener(){
  2. intinitX;
  3. intinitY;
  4. booleansetInitialPosition;
  5. publicbooleanonTouch(Viewv,MotionEventevent){
  6. if(mState==State.ANIMATING){
  7. //weareanimating
  8. returnfalse;
  9. }
  10. /Log.d(TAG,"state:"+mState+"x:"+event.getX()+"y:"+event.getY());
  11. intaction=event.getAction();
  12. if(action==MotionEvent.ACTION_DOWN){
  13. if(mBringToFront){
  14. bringToFront();
  15. }
  16. initX=0;
  17. initY=0;
  18. if(mContent.getVisibility()==GONE){
  19. //sincewemaynotknowcontentdimensionsweusefactorshere
  20. if(mOrientation==VERTICAL){
  21. initY=mPosition==TOP?-1:1;
  22. }else{
  23. initX=mPosition==LEFT?-1:1;
  24. }
  25. }
  26. setInitialPosition=true;
  27. }else{
  28. if(setInitialPosition){
  29. //nowweknowcontentdimensions,sowemultiplyfactors...
  30. initX*=mContentWidth;
  31. initY*=mContentHeight;
  32. //...andsetinitialpanel'sposition
  33. mGestureListener.setScroll(initX,initY);
  34. setInitialPosition=false;
  35. //foroffsetLocationwehavetoinvertvalues
  36. initX=-initX;
  37. initY=-initY;
  38. }
  39. //offseteveryACTION_MOVE&ACTION_UPevent
  40. event.offsetLocation(initX,initY);
  41. }
  42. if(!mGestureDetector.onTouchEvent(event)){
  43. if(action==MotionEvent.ACTION_UP){
  44. //tupupafterscrolling
  45. post(startAnimation);
  46. }
  47. }
  48. returnfalse;
  49. }
  50. };

替换为:

[java] view plain copy
  1. OnTouchListenertouchListener=newOnTouchListener(){
  2. floattouchX,touchY;
  3. publicbooleanonTouch(Viewv,MotionEventevent){
  4. if(mState==State.ANIMATING){
  5. //weareanimating
  6. returnfalse;
  7. }
  8. intaction=event.getAction();
  9. if(action==MotionEvent.ACTION_DOWN){
  10. if(mBringToFront){
  11. bringToFront();
  12. }
  13. touchX=event.getX();
  14. touchY=event.getY();
  15. }
  16. if(!mGestureDetector.onTouchEvent(event)){
  17. if(action==MotionEvent.ACTION_UP){
  18. //tupupafterscrolling
  19. intsize=(int)(Math.abs(touchX-event.getX())+Math
  20. .abs(touchY-event.getY()));
  21. if(size==mContentWidth||size==mContentHeight){
  22. mState=State.ABOUT_TO_ANIMATE;
  23. //Log.e("size",String.valueOf(size));
  24. //Log.e(String.valueOf(mContentWidth),String.valueOf(mContentHeight));
  25. }
  26. post(startAnimation);
  27. }
  28. }
  29. returnfalse;
  30. }
  31. };

即可修复这个bug,并且也同样实现了OnClickListener的功能,可以把原Panel的OnClickListener给删掉了!







http://blog.csdn.net/hellogv/article/details/6264706

http://blog.csdn.net/hellogv/article/details/6264706

http://blog.csdn.net/hellogv/article/details/6264706


Android提高第十九篇之"多方向"抽屉

分类:Android提高 42640人阅读 评论(135) 收藏 举报 android action up google float 扩展

本文来自http://blog.csdn.net/hellogv/,引用必须注明出处!

在android上要实现类似Launch的抽屉效果,大家一定首先会想起SlidingDrawer。SlidingDrawer是android官方控件之一,本文的主角不是它,而是民间的控件工具集合~~~android-misc-widgets。android-misc-widgets里面包含几个widget:Panel、SmoothButton、Switcher、VirtualKeyboard,还有一些动画特效,本文主要介绍抽屉容器Panel的用法。android-misc-widgets的google工程地址:-widgets/http://code.google.com/p/android-misc,工程代码中Panel的演示效果如下:

可动态布局的Android抽屉之基础_第4张图片

这个Panel控件可以轻易实现不同方向的抽屉效果,比SlidingDrawer有更强的扩展性!

在多次使用Panel的过程中,发现Panel有个bug,会间断性出现“闪烁”,也就是在onTouchListener里面的触发ACTION_DOWN后,抽屉瞬间弹出然后瞬间回收(版本日期为Feb 3, 2009)。把原Panel的OnTouchListener,即以下代码:

[java] view plain copy
  1. OnTouchListenertouchListener=newOnTouchListener(){
  2. intinitX;
  3. intinitY;
  4. booleansetInitialPosition;
  5. publicbooleanonTouch(Viewv,MotionEventevent){
  6. if(mState==State.ANIMATING){
  7. //weareanimating
  8. returnfalse;
  9. }
  10. /Log.d(TAG,"state:"+mState+"x:"+event.getX()+"y:"+event.getY());
  11. intaction=event.getAction();
  12. if(action==MotionEvent.ACTION_DOWN){
  13. if(mBringToFront){
  14. bringToFront();
  15. }
  16. initX=0;
  17. initY=0;
  18. if(mContent.getVisibility()==GONE){
  19. //sincewemaynotknowcontentdimensionsweusefactorshere
  20. if(mOrientation==VERTICAL){
  21. initY=mPosition==TOP?-1:1;
  22. }else{
  23. initX=mPosition==LEFT?-1:1;
  24. }
  25. }
  26. setInitialPosition=true;
  27. }else{
  28. if(setInitialPosition){
  29. //nowweknowcontentdimensions,sowemultiplyfactors...
  30. initX*=mContentWidth;
  31. initY*=mContentHeight;
  32. //...andsetinitialpanel'sposition
  33. mGestureListener.setScroll(initX,initY);
  34. setInitialPosition=false;
  35. //foroffsetLocationwehavetoinvertvalues
  36. initX=-initX;
  37. initY=-initY;
  38. }
  39. //offseteveryACTION_MOVE&ACTION_UPevent
  40. event.offsetLocation(initX,initY);
  41. }
  42. if(!mGestureDetector.onTouchEvent(event)){
  43. if(action==MotionEvent.ACTION_UP){
  44. //tupupafterscrolling
  45. post(startAnimation);
  46. }
  47. }
  48. returnfalse;
  49. }
  50. };

替换为:

[java] view plain copy
  1. OnTouchListenertouchListener=newOnTouchListener(){
  2. floattouchX,touchY;
  3. publicbooleanonTouch(Viewv,MotionEventevent){
  4. if(mState==State.ANIMATING){
  5. //weareanimating
  6. returnfalse;
  7. }
  8. intaction=event.getAction();
  9. if(action==MotionEvent.ACTION_DOWN){
  10. if(mBringToFront){
  11. bringToFront();
  12. }
  13. touchX=event.getX();
  14. touchY=event.getY();
  15. }
  16. if(!mGestureDetector.onTouchEvent(event)){
  17. if(action==MotionEvent.ACTION_UP){
  18. //tupupafterscrolling
  19. intsize=(int)(Math.abs(touchX-event.getX())+Math
  20. .abs(touchY-event.getY()));
  21. if(size==mContentWidth||size==mContentHeight){
  22. mState=State.ABOUT_TO_ANIMATE;
  23. //Log.e("size",String.valueOf(size));
  24. //Log.e(String.valueOf(mContentWidth),String.valueOf(mContentHeight));
  25. }
  26. post(startAnimation);
  27. }
  28. }
  29. returnfalse;
  30. }
  31. };

即可修复这个bug,并且也同样实现了OnClickListener的功能,可以把原Panel的OnClickListener给删掉了!


更多相关文章

  1. android抽屉效果的实现
  2. webView组件使用指南
  3. react-native-picker滚轮组件的使用
  4. Android 日历方式显示的日期选择组件(日历控件之一)
  5. [android]android5大基础组件深入分析
  6. Android中的基础组件
  7. Android 建立文件夹、生成文件并写入文本文件内容
  8. Android多组件下Gradle统一配置

随机推荐

  1. 老版本ndk 下载链接
  2. Android 自定义弹出菜单和对话框
  3. 科幻世界iPhone、iPad、Android手机客户
  4. android启动一个应用工具类
  5. 你好,Android 11
  6. android jni 调用static native void met
  7. android sensorsimulator使用介绍
  8. Android(安卓)SDK 离线下载安装
  9. android 9.0 收到通知消息亮屏
  10. android 设置标题