Android 3D滑动菜单实现及源代码.doc_第1页
Android 3D滑动菜单实现及源代码.doc_第2页
Android 3D滑动菜单实现及源代码.doc_第3页
Android 3D滑动菜单实现及源代码.doc_第4页
Android 3D滑动菜单实现及源代码.doc_第5页
已阅读5页,还剩15页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Android 3D滑动菜单完全解析,实现推拉门式的立体特效在上一篇文章中,我们学习了Camera的基本用法,并借助它们编写了一个例子,实现了类似于API Demos里的图片中轴旋转功能。不过那个例子的核心代码是来自于API Demos中带有的Rotate3dAnimation这个类,是它帮助我们完成了所有的三维旋转操作,所有Matrix和Camera相关的代码也是封装在这个类中。这样说来的话,大家心里会不会痒痒的呢?虽然学习了Camera的用法,但却没有按照自己的理解来实现一套非常炫酷的3D效果。不要着急,今天我就带着大家一起来实现一种3D推拉门式的滑动菜单,而且完全不会借助任何API Demos里面的代码。当然如果你还不是很了解Camera的使用方式,可以先去阅读我的上一篇文章Android中轴旋转特效实现,制作别样的图片浏览器。关于滑动菜单的文章我也已经写过好几篇了,相信看过的朋友对滑动菜单的实现方式应该都已经比较熟悉了,那么本篇文章的重点就在于,如何在传统滑动菜单的基础上加入推拉门式的立体效果。还不了解滑动菜单如何实现的朋友,可以去翻一翻我之前的文章。说到这里我必须要吐槽一下了,最近发现有不少的网站和个人将我的文章恶意转走,而且还特意把第一行的原文地址信息去除掉。更可气的是,在百度上搜索我文章的标题时,竟然先找到的是那些转载我文章的网站。唉,伤心了,看来还是谷歌比较正常。因此今天我也是在这里特别申明一下,我所写的所有文章均是首发于CSDN博客,如果你阅读这篇文章时是在别的网站,那么你将无法找到我前面所写的关于传统滑动菜单的文章,而且你的疑问和留言也将得不到解答。下面还是回到正题,首先来讲一下这次的实现原理吧,其实传统的滑动菜单功能就是把菜单部分放在了下面,主布局放在了上面,然后根据手指滑动的距离来偏移主布局,让菜单部分得以显示出来就行了。不过我们这次既然要做推拉门式的立体效果,就需要将传统的思维稍微转变一下,可以先让菜单部分隐藏掉,但却复制一个菜单的镜像并生成一张图片,然后在手指滑动的时候对这张图片进行三维操作,让它产生推拉门式的效果,等滑动操作结束的时候,才让真正的菜单显示出来,然后将这个图片隐藏。原理示意图如下所示: 那么下面我们就开始动手实现吧,首先新建一个Android项目,起名叫做ThreeDSlidingLayoutDemo。然后新建一个Image3dView类继承自View,用于生成镜像图片,以及完成三维操作,代码如下所示:javaview plaincopy1. publicclassImage3dViewextendsView2. 3. /*4. *源视图,用于生成图片对象。5. */6. privateViewsourceView;7. 8. /*9. *根据传入的源视图生成的图片对象。10. */11. privateBitmapsourceBitmap;12. 13. /*14. *源视图的宽度。15. */16. privatefloatsourceWidth;17. 18. /*19. *Matrix对象,用于对图片进行矩阵操作。20. */21. privateMatrixmatrix=newMatrix();22. 23. /*24. *Camera对象,用于对图片进行三维操作。25. */26. privateCameracamera=newCamera();27. 28. /*29. *Image3dView的构造函数30. *31. *paramcontext32. *paramattrs33. */34. publicImage3dView(Contextcontext,AttributeSetattrs)35. super(context,attrs);36. 37. 38. /*39. *提供外部接口,允许向Image3dView传入源视图。40. *41. *paramview42. *传入的源视图43. */44. publicvoidsetSourceView(Viewview)45. sourceView=view;46. sourceWidth=sourceView.getWidth();47. 48. 49. /*50. *清除掉缓存的图片对象。51. */52. publicvoidclearSourceBitmap()53. if(sourceBitmap!=null)54. sourceBitmap=null;55. 56. 57. 58. Override59. protectedvoidonDraw(Canvascanvas)60. super.onDraw(canvas);61. if(sourceBitmap=null)62. getSourceBitmap();63. 64. /计算图片需要旋转的角度65. floatdegree=90-(90/sourceWidth)*getWidth();66. camera.save();67. camera.rotateY(degree);68. camera.getMatrix(matrix);69. camera.restore();70. /将旋转的中心点移动到屏幕左边缘的中间位置71. matrix.preTranslate(0,-getHeight()/2);72. matrix.postTranslate(0,getHeight()/2);73. canvas.drawBitmap(sourceBitmap,matrix,null);74. 75. 76. /*77. *获取源视图对应的图片对象。78. */79. privatevoidgetSourceBitmap()80. if(sourceView!=null)81. sourceView.setDrawingCacheEnabled(true);82. sourceView.layout(0,0,sourceView.getWidth(),sourceView.getHeight();83. sourceView.buildDrawingCache();84. sourceBitmap=sourceView.getDrawingCache();85. 86. 87. 88. 可以看到,Image3dView中提供了一个setSourceView()方法,用于传递源视图进来,我们稍后复制镜像就是对它进行复制。然后在onDraw()方法里对sourceBitmap进行判断,如果为空,则去调用getSourceBitmap()方法来生成一张镜像图片,getSourceBitmap()方法的细节大家自己去看。在获得了镜像图片之后,接下来就是要计算图片的旋转角度了,这里根据Image3dView当前的宽度和源视图的总宽度进行对比,按比例算出旋转的角度。然后调用Camera的rotateY()方法,让图片团练Y轴进行旋转,并将旋转的中心点移动到屏幕左边缘的中间位置,这几行代码我们在上篇文章中已经见过了,算是挺熟悉了吧!最后调用Canvas的drawBitmap()方法把图片绘制出来。完成了Image3dView之后,接着我们要开始编写滑动菜单部分的代码,其实这次的代码和之前的滑动菜单代码大同小异,看过我前面文章的朋友,这次理解起来一定会轻而易举。新建ThreeDSlidingLayout类,代码如下所示:javaview plaincopy1. publicclassThreeDSlidingLayoutextendsRelativeLayoutimplementsOnTouchListener2. 3. /*4. *滚动显示和隐藏左侧布局时,手指滑动需要达到的速度。5. */6. publicstaticfinalintSNAP_VELOCITY=200;7. 8. /*9. *滑动状态的一种,表示未进行任何滑动。10. */11. publicstaticfinalintDO_NOTHING=0;12. 13. /*14. *滑动状态的一种,表示正在滑出左侧菜单。15. */16. publicstaticfinalintSHOW_MENU=1;17. 18. /*19. *滑动状态的一种,表示正在隐藏左侧菜单。20. */21. publicstaticfinalintHIDE_MENU=2;22. 23. /*24. *记录当前的滑动状态25. */26. privateintslideState;27. 28. /*29. *屏幕宽度值。30. */31. privateintscreenWidth;32. 33. /*34. *右侧布局最多可以滑动到的左边缘。35. */36. privateintleftEdge=0;37. 38. /*39. *右侧布局最多可以滑动到的右边缘。40. */41. privateintrightEdge=0;42. 43. /*44. *在被判定为滚动之前用户手指可以移动的最大值。45. */46. privateinttouchSlop;47. 48. /*49. *记录手指按下时的横坐标。50. */51. privatefloatxDown;52. 53. /*54. *记录手指按下时的纵坐标。55. */56. privatefloatyDown;57. 58. /*59. *记录手指移动时的横坐标。60. */61. privatefloatxMove;62. 63. /*64. *记录手指移动时的纵坐标。65. */66. privatefloatyMove;67. 68. /*69. *记录手机抬起时的横坐标。70. */71. privatefloatxUp;72. 73. /*74. *左侧布局当前是显示还是隐藏。只有完全显示或隐藏时才会更改此值,滑动过程中此值无效。75. */76. privatebooleanisLeftLayoutVisible;77. 78. /*79. *是否正在滑动。80. */81. privatebooleanisSliding;82. 83. /*84. *是否已加载过一次layout,这里onLayout中的初始化只需加载一次85. */86. privatebooleanloadOnce;87. 88. /*89. *左侧布局对象。90. */91. privateViewleftLayout;92. 93. /*94. *右侧布局对象。95. */96. privateViewrightLayout;97. 98. /*99. *在滑动过程中展示的3D视图100. */101. privateImage3dViewimage3dView;102. 103. /*104. *用于监听侧滑事件的View。105. */106. privateViewmBindView;107. 108. /*109. *左侧布局的参数,通过此参数来重新确定左侧布局的宽度,以及更改leftMargin的值。110. */111. privateMarginLayoutParamsleftLayoutParams;112. 113. /*114. *右侧布局的参数,通过此参数来重新确定右侧布局的宽度。115. */116. privateMarginLayoutParamsrightLayoutParams;117. 118. /*119. *3D视图的参数,通过此参数来重新确定3D视图的宽度。120. */121. privateViewGroup.LayoutParamsimage3dViewParams;122. 123. /*124. *用于计算手指滑动的速度。125. */126. privateVelocityTrackermVelocityTracker;127. 128. /*129. *重写SlidingLayout的构造函数,其中获取了屏幕的宽度。130. *131. *paramcontext132. *paramattrs133. */134. publicThreeDSlidingLayout(Contextcontext,AttributeSetattrs)135. super(context,attrs);136. WindowManagerwm=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);137. screenWidth=wm.getDefaultDisplay().getWidth();138. touchSlop=ViewConfiguration.get(context).getScaledTouchSlop();139. 140. 141. /*142. *绑定监听侧滑事件的View,即在绑定的View进行滑动才可以显示和隐藏左侧布局。143. *144. *parambindView145. *需要绑定的View对象。146. */147. publicvoidsetScrollEvent(ViewbindView)148. mBindView=bindView;149. mBindView.setOnTouchListener(this);150. 151. 152. /*153. *将屏幕滚动到左侧布局界面,滚动速度设定为10.154. */155. publicvoidscrollToLeftLayout()156. image3dView.clearSourceBitmap();157. newScrollTask().execute(-10);158. 159. 160. /*161. *将屏幕滚动到右侧布局界面,滚动速度设定为-10.162. */163. publicvoidscrollToRightLayout()164. image3dView.clearSourceBitmap();165. newScrollTask().execute(10);166. 167. 168. /*169. *左侧布局是否完全显示出来,或完全隐藏,滑动过程中此值无效。170. *171. *return左侧布局完全显示返回true,完全隐藏返回false。172. */173. publicbooleanisLeftLayoutVisible()174. returnisLeftLayoutVisible;175. 176. 177. /*178. *在onLayout中重新设定左侧布局和右侧布局的参数。179. */180. Override181. protectedvoidonLayout(booleanchanged,intl,intt,intr,intb)182. super.onLayout(changed,l,t,r,b);183. if(changed&!loadOnce)184. /获取左侧布局对象185. leftLayout=findViewById(R.id.menu);186. leftLayoutParams=(MarginLayoutParams)leftLayout.getLayoutParams();187. rightEdge=-leftLayoutParams.width;188. /获取右侧布局对象189. rightLayout=findViewById(R.id.content);190. rightLayoutParams=(MarginLayoutParams)rightLayout.getLayoutParams();191. rightLayoutParams.width=screenWidth;192. rightLayout.setLayoutParams(rightLayoutParams);193. /获取3D视图对象194. image3dView=(Image3dView)findViewById(R.id.image_3d_view);195. /将左侧布局传入3D视图中作为生成源196. image3dView.setSourceView(leftLayout);197. loadOnce=true;198. 199. 200. 201. Override202. publicbooleanonTouch(Viewv,MotionEventevent)203. createVelocityTracker(event);204. switch(event.getAction()205. caseMotionEvent.ACTION_DOWN:206. /手指按下时,记录按下时的横坐标207. xDown=event.getRawX();208. yDown=event.getRawY();209. slideState=DO_NOTHING;210. break;211. caseMotionEvent.ACTION_MOVE:212. /手指移动时,对比按下时的横坐标,计算出移动的距离,来调整右侧布局的leftMargin值,从而显示和隐藏左侧布局213. xMove=event.getRawX();214. yMove=event.getRawY();215. intmoveDistanceX=(int)(xMove-xDown);216. intmoveDistanceY=(int)(yMove-yDown);217. checkSlideState(moveDistanceX,moveDistanceY);218. switch(slideState)219. caseSHOW_MENU:220. rightLayoutParams.rightMargin=-moveDistanceX;221. onSlide();222. break;223. caseHIDE_MENU:224. rightLayoutParams.rightMargin=rightEdge-moveDistanceX;225. onSlide();226. break;227. default:228. break;229. 230. break;231. caseMotionEvent.ACTION_UP:232. xUp=event.getRawX();233. intupDistanceX=(int)(xUp-xDown);234. if(isSliding)235. /手指抬起时,进行判断当前手势的意图236. switch(slideState)237. caseSHOW_MENU:238. if(shouldScrollToLeftLayout()239. scrollToLeftLayout();240. else241. scrollToRightLayout();242. 243. break;244. caseHIDE_MENU:245. if(shouldScrollToRightLayout()246. scrollToRightLayout();247. else248. scrollToLeftLayout();249. 250. break;251. default:252. break;253. 254. elseif(upDistanceX=touchSlop&moveDistanceX=touchSlop&moveDistanceX0303. &Math.abs(moveDistanceY)leftEdge)314. rightLayoutParams.rightMargin=leftEdge;315. elseif(rightLayoutParams.rightMarginleftLayoutParams.width/2|getScrollVelocity()SNAP_VELOCITY;328. 329. 330. /*331. *判断是否应该滚动将右侧布局展示出来。如果手指移动距离加上leftLayoutPadding大于屏幕的1/2,332. *或者手指移动速度大于SNAP_VELOCITY,就认为应该滚动将右侧布局展示出来。333. *334. *return如果应该滚动将右侧布局展示出来返回true,否则返回false。335. */336. privatebooleanshouldScrollToRightLayout()337. returnxDown-xUpleftLayoutParams.width/2|getScrollVelocity()SNAP_VELOCITY;338. 339. 340. /*341. *创建VelocityTracker对象,并将触摸事件加入到VelocityTracker当中。342. *343. *paramevent344. *右侧布局监听控件的滑动事件345. */346. privatevoidcreateVelocityTracker(MotionEventevent)347. if(mVelocityTracker=null)348. mVelocityTracker=VelocityTracker.obtain();349. 350. mVelocityTracker.addMovement(event);351. 352. 353. /*354. *获取手指在右侧布局的监听View上的滑动速度。355. *356. *return滑动速度,以每秒钟移动了多少像素值为单位。357. */358. privateintgetScrollVelocity()359. mVelocityTputeCurrentVelocity(1000);360. intvelocity=(int)mVelocityTracker.getXVelocity();361. returnMath.abs(velocity);362. 363. 364. /*365. *回收VelocityTracker对象。366. */367. privatevoidrecycleVelocityTracker()368. mVelocityTracker.recycle();369. mVelocityTracker=null;370. 371. 372. /*373. *使用可以获得焦点的控件在滑动的时候失去焦点。374. */375. privatevoidunFocusBindView()376. if(mBindView!=null)377. mBindView.setPressed(false);378. mBindView.setFocusable(false);379. mBindView.setFocusableInTouchMode(false);380. 381. 382. 383. /*384. *保证此时让左侧布局不可见,3D视图可见,从而让滑动过程中产生3D的效果。385. */386. privatevoidshowImage3dView()387. if(image3dView.getVisibility()!=View.VISIBLE)388. image3dView.setVisibility(View.VISIBLE);389. 390. if(leftLayout.getVisibility()!=View.INVISIBLE)391. leftLayout.setVisibility(View.INVISIBLE);392. 393. 394. 395. classScrollTaskextendsAsyncTask396. 397. Override398. protectedIntegerdoInBackground(Integer.speed)399. intrightMargin=rightLayoutParams.rightMargin;400. /根据传入的速度来滚动界面,当滚动到达左边界或右边界时,跳出循环。401. while(true)402. rightMargin=rightMargin+speed0;403. if(rightMarginleftEdge)408. rightMargin=leftEdge;409. break;410. 411. publishProgress(rightMargin);412. /为了要有滚动效果产生,每次循环使线程睡眠5毫秒,这样肉眼才能够看到滚动动画。413. sleep(5);414. 415. if(speed00)416. isLeftLayout

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论