【移动应用开发技术】Android如何实现3D推拉门式滑动菜单_第1页
【移动应用开发技术】Android如何实现3D推拉门式滑动菜单_第2页
【移动应用开发技术】Android如何实现3D推拉门式滑动菜单_第3页
【移动应用开发技术】Android如何实现3D推拉门式滑动菜单_第4页
【移动应用开发技术】Android如何实现3D推拉门式滑动菜单_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

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

文档简介

【移动应用开发技术】Android如何实现3D推拉门式滑动菜单

在下给大家分享一下Android如何实现3D推拉门式滑动菜单,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!实现  我们先来看一下示意图:  下面我就来分析一下源码。  从效果图中可以看到的是,滑动的时候菜单会有一个效果,这个效果是沿y轴旋转的效果,这种效果是用Matrix和Camera来实现,具体怎么实现的我在另一篇文章《对Matrix中preTranslate()和postTranslate()的理解》中做了简单的说明,可以很容易的实现这样的效果。  在Image3DView中,我们封装了这样的效果,只要传入左侧菜单界面的View,然后就可以实现了。  先来看一下布局文件:<com.example.sliding3dlayout.Sliding3DLayout

xmlns:android="/apk/res/android"

xmlns:tools="/tools"

android:id="@+id/slidingLayout"

android:layout_width="match_parent"

android:layout_height="match_parent">

<RelativeLayout

android:layout_height="fill_parent"

android:layout_width="240dp"

android:background="#333333"

android:visibility="invisible"

>

<LinearLayout

android:layout_centerInParent="true"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:orientation="vertical"

>

<TextView

android:layout_width="fill_parent"

android:layout_height="50dp"

android:text="登录"

android:gravity="center"

android:textColor="#ffffff"

/>

<TextView

android:layout_width="fill_parent"

android:layout_height="50dp"

android:text="注册"

android:gravity="center"

android:textColor="#ffffff"

/>

<TextView

android:layout_width="fill_parent"

android:layout_height="50dp"

android:text="退出"

android:gravity="center"

android:textColor="#ffffff"

/>

</LinearLayout>

</RelativeLayout>

<LinearLayout

android:id="@+id/content"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:layout_alignParentRight="true"

android:background="#ffffff"

android:orientation="vertical">

<Button

android:id="@+id/menuButton"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Menu"

/>

<ListView

android:id="@+id/contentList"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:cacheColorHint="#00000000"

>

</ListView>

</LinearLayout>

</com.example.sliding3dlayout.Sliding3DLayout>  Sliding3DLayout类是定义的该菜单控件,里面有两个主要的视图,第一个是菜单视图,第二个就是主界面视图。当滑动的时候,我们把左侧的菜单视图隐藏,然后显示Image3DView控件,也就是沿y轴旋转,根据滑动的距离,旋转的角度在不断变化,Image3DView的视图也在不断的变化,当菜单完全显示的时候,就显示左侧菜单的界面,然后将Image3DView隐藏,这样就实现了所谓的滑动动画。public

class

Sliding3DLayout

extends

RelativeLayout

implements

OnTouchListener{

//滚动显示和隐藏左侧布局时,手指滑动需要达到的速度。

public

static

final

int

SNAP_VELOCITY

=

200;

//滑动状态的一种,表示未进行任何滑动。

public

static

final

int

DO_NOTHING

=

0;

//滑动状态的一种,表示正在滑出左侧菜单。

public

static

final

int

SHOW_MENU

=

1;

//滑动状态的一种,表示正在隐藏左侧菜单。

public

static

final

int

HIDE_MENU

=

2;

//记录当前的滑动状态

private

int

slideState;

//屏幕宽度值。

private

int

screenWidth;

//右侧布局最多可以滑动到的左边缘。

private

int

leftEdge

=

0;

//右侧布局最多可以滑动到的右边缘。

private

int

rightEdge

=

0;

//在被判定为滚动之前用户手指可以移动的最大值。

private

int

touchSlop;

//记录手指按下时的横坐标。

private

float

xDown;

//记录手指按下时的纵坐标。

private

float

yDown;

//记录手指移动时的横坐标。

private

float

xMove;

//记录手指移动时的纵坐标。

private

float

yMove;

//记录手机抬起时的横坐标。

private

float

xUp;

//左侧布局当前是显示还是隐藏。只有完全显示或隐藏时才会更改此值,滑动过程中此值无效。

private

boolean

isLeftLayoutVisible;

//是否正在滑动。

private

boolean

isSliding;

//是否已加载过一次layout,这里onLayout中的初始化只需加载一次

private

boolean

loadOnce;

//左侧布局对象。

private

View

leftLayout;

//右侧布局对象。

private

View

rightLayout;

//在滑动过程中展示的3D视图

private

Image3DView

image3dView;

//用于监听侧滑事件的View。

private

View

mBindView;

//左侧布局的参数,通过此参数来重新确定左侧布局的宽度,以及更改leftMargin的值。

private

MarginLayoutParams

leftLayoutParams;

//右侧布局的参数,通过此参数来重新确定右侧布局的宽度。

private

MarginLayoutParams

rightLayoutParams;

//3D视图的参数,通过此参数来重新确定3D视图的宽度。

private

ViewGroup.LayoutParams

image3dViewParams;

//用于计算手指滑动的速度。

private

VelocityTracker

mVelocityTracker;

public

Sliding3DLayout(Context

context,

AttributeSet

attrs){

super(context,

attrs);

WindowManager

wm

=

(WindowManager)

context.getSystemService(Context.WINDOW_SERVICE);

screenWidth

=

wm.getDefaultDisplay().getWidth();

touchSlop

=

ViewConfiguration.get(context).getScaledTouchSlop();

}

public

Sliding3DLayout(Context

context){

this(context,null);

}

/**

*

左侧布局是否完全显示出来,或完全隐藏,滑动过程中此值无效。

*

@return

左侧布局完全显示返回true,完全隐藏返回false。

*/

public

boolean

isLeftLayoutVisible(){

return

isLeftLayoutVisible;

}

/**

*

绑定监听侧滑事件的View,即在绑定的View进行滑动才可以显示和隐藏左侧布局。

*

@param

v

*

需要绑定的View对象。

*/

public

void

setScrollEvent(View

v){

mBindView

=

v;

mBindView.setOnTouchListener(this);

}

@Override

public

boolean

onTouch(View

v,

MotionEvent

event){

createVelocityTracker(event);

switch(event.getAction()){

case

MotionEvent.ACTION_DOWN:

xDown

=

event.getRawX();

yDown

=

event.getRawY();

slideState

=

DO_NOTHING

;

break;

case

MotionEvent.ACTION_MOVE:

//

手指移动时,对比按下时的横坐标,计算出移动的距离,来调整右侧布局的leftMargin值,从而显示和隐藏左侧布局

xMove

=

event.getRawX();

yMove

=

event.getRawY();

int

moveDistanceX

=

(int)(xMove

-

xDown);

int

moveDistanceY

=

(int)(yMove

-

yDown);

checkSlideState(moveDistanceX,

moveDistanceY);

switch(slideState){

case

SHOW_MENU:

rightLayoutParams.rightMargin

=

-moveDistanceX;

onSlide();

break;

case

HIDE_MENU:

rightLayoutParams.rightMargin

=

rightEdge

-

moveDistanceX;

onSlide();

break;

default:

break;

}

break;

case

MotionEvent.ACTION_UP:

xUp

=

event.getRawX();

int

upDistanceX

=

(int)(xUp

-

xDown);

if(isSliding){

switch

(slideState){

case

SHOW_MENU:

if(shouldScrollToLeftLayout()){

scrollToLeftLayout();

}else{

scrollToRightLayout();

}

break;

case

HIDE_MENU:

if(shouldScrollToRightLayout()){

scrollToRightLayout();

}else{

scrollToLeftLayout();

}

break;

}

}else

if

(upDistanceX

<

touchSlop

&&

isLeftLayoutVisible){

scrollToRightLayout();

}

recycleVelocityTracker();

break;

}

if

(v.isEnabled()){

if

(isSliding){

unFocusBindView();

return

true;

}

if

(isLeftLayoutVisible)

{

return

true;

}

return

false;

}

return

true;

}

@Override

protected

void

onLayout(boolean

changed,

int

l,

int

t,

int

r,

int

b)

{

super.onLayout(changed,

l,

t,

r,

b);

if(changed&&!loadOnce){

//获取左侧菜单布局

leftLayout

=

getChildAt(0);

leftLayoutParams

=

(MarginLayoutParams)leftLayout.getLayoutParams();

rightEdge

=

-leftLayoutParams.width;

//获取右侧布局

rightLayout

=

getChildAt(1);

rightLayoutParams

=

(MarginLayoutParams)rightLayout.getLayoutParams();

rightLayoutParams.width

=

screenWidth;

rightLayout.setLayoutParams(rightLayoutParams);

image3dView

=

new

Image3DView(getContext());

/*ViewGroup.LayoutParams

params

=

new

LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT,

android.view.ViewGroup.LayoutParams.WRAP_CONTENT);*/

image3dView.setVisibility(INVISIBLE);

addView(image3dView);

//

将左侧布局传入3D视图中作为生成源

image3dView.setSourceView(leftLayout);

loadOnce

=

true;

}

}

/**

*

回收VelocityTracker对象。

*/

private

void

recycleVelocityTracker()

{

mVelocityTracker.recycle();

mVelocityTracker

=

null;

}

/**

*

将屏幕滚动到左侧布局界面,滚动速度设定为10.

*/

public

void

scrollToLeftLayout(){

image3dView.clearSourceBitmap();

new

ScrollTask().execute(-10);

}

/**

*

将屏幕滚动到右侧布局界面,滚动速度设定为-10.

*/

public

void

scrollToRightLayout(){

image3dView.clearSourceBitmap();

new

ScrollTask().execute(10);

}

/**

*

获取手指在右侧布局的监听View上的滑动速度。

*

*

@return

滑动速度,以每秒钟移动了多少像素值为单位。

*/

private

int

getScrollVelocity()

{

mVelocityTputeCurrentVelocity(1000);

int

velocity

=

(int)

mVelocityTracker.getXVelocity();

return

Math.abs(velocity);

}

/**

*

判断是否应该滚动将左侧布局展示出来。如果手指移动距离大于屏幕的1/2,或者手指移动速度大于SNAP_VELOCITY,

*

就认为应该滚动将左侧布局展示出来。

*

*

@return

如果应该滚动将左侧布局展示出来返回true,否则返回false。

*/

private

boolean

shouldScrollToLeftLayout()

{

return

xUp

-

xDown

>

leftLayoutParams.width

/

2

||

getScrollVelocity()

>

SNAP_VELOCITY;

}

/**

*

判断是否应该滚动将右侧布局展示出来。如果手指移动距离加上leftLayoutPadding大于屏幕的1/2,

*

或者手指移动速度大于SNAP_VELOCITY,

就认为应该滚动将右侧布局展示出来。

*

*

@return

如果应该滚动将右侧布局展示出来返回true,否则返回false。

*/

private

boolean

shouldScrollToRightLayout(){

return

xDown

-

xUp

>

leftLayoutParams.width

/

2

||

getScrollVelocity()

>

SNAP_VELOCITY;

}

/**

*

执行滑动过程中的逻辑操作,如边界检查,改变偏移值,可见性检查等。

*/

private

void

onSlide(){

checkSlideBorder();

rightLayout.setLayoutParams(rightLayoutParams);

image3dView.clearSourceBitmap();

image3dViewParams

=

image3dView.getLayoutParams();

image3dViewParams.width

=

-rightLayoutParams.rightMargin;

//滑动的同时改变3D视图的大小

image3dView.setLayoutParams(image3dViewParams);

showImage3dView();

}

public

void

toggle(){

if(isLeftLayoutVisible())

scrollToRightLayout();

else

scrollToLeftLayout();

}

/**

*

保证此时让左侧布局不可见,3D视图可见,从而让滑动过程中产生3D的效果。

*/

private

void

showImage3dView()

{

if

(image3dView.getVisibility()

!=

View.VISIBLE)

{

image3dView.setVisibility(View.VISIBLE);

}

if

(leftLayout.getVisibility()

!=

View.INVISIBLE)

{

leftLayout.setVisibility(View.INVISIBLE);

}

}

/**

*

在滑动过程中检查左侧菜单的边界值,防止绑定布局滑出屏幕。

*/

private

void

checkSlideBorder(){

if

(rightLayoutParams.rightMargin

>

leftEdge){

rightLayoutParams.rightMargin

=

leftEdge;

}

else

if

(rightLayoutParams.rightMargin

<

rightEdge)

{

rightLayoutParams.rightMargin

=

rightEdge;

}

}

/**

*

根据手指移动的距离,判断当前用户的滑动意图,然后给slideState赋值成相应的滑动状态值。

*

*

@param

moveDistanceX

*

横向移动的距离

*

@param

moveDistanceY

*

纵向移动的距离

*/

private

void

checkSlideState(int

moveDistanceX,

int

moveDistanceY)

{

if

(isLeftLayoutVisible)

{

//如果是向左滑动,则是想隐藏菜单

if

(!isSliding

&&

Math.abs(moveDistanceX)

>=

touchSlop

&&

moveDistanceX

<

0)

{

isSliding

=

true;

slideState

=

HIDE_MENU;

}

}//向右滑动则是显示菜单

else

if

(!isSliding

&&

Math.abs(moveDistanceX)

>=

touchSlop

&&

moveDistanceX

>

0

&&

Math.abs(moveDistanceY)

<

touchSlop)

{

isSliding

=

true;

slideState

=

SHOW_MENU;

}

}

/**

*

创建VelocityTracker对象,并将触摸事件加入到VelocityTracker当中。

*

*

@param

event

*

右侧布局监听控件的滑动事件

*/

private

void

createVelocityTracker(MotionEvent

event)

{

if

(mVelocityTracker

==

null)

{

mVelocityTracker

=

VelocityTracker.obtain();

}

mVelocityTracker.addMovement(event);

}

class

ScrollTask

extends

AsyncTask<Integer,

Integer,

Integer>{

@Override

protected

Integer

doInBackground(Integer...

speed){

int

rightMargin

=

rightLayoutParams.rightMargin;

//

根据传入的速度来滚动界面,当滚动到达左边界或右边界时,跳出循环。

while(true){

rightMargin+=speed[0];

if

(rightMargin

<

rightEdge)

{

rightMargin

=

rightEdge;

break;

}

if

(rightMargin

>

leftEdge)

{

rightMargin

=

leftEdge;

break;

}

publishProgress(rightMargin);

//

为了要有滚动效果产生,每次循环使线程睡眠5毫秒,这样肉眼才能够看到滚动动画。

sleep(5);

}

if

(speed[0]

>

0){

isLeftLayoutVisible

=

false;

}

else

{

isLeftLayoutVisible

=

true;

}

isSliding

=

false;

return

rightMargin;

}

@Override

protected

void

onProgressUpdate(Integer...

rightMargin)

{

rightLayoutParams.rightMargin

=

rightMargin[0];

rightLayout.setLayoutParams(rightLayoutParams);

image3dViewParams

=

image3dView.getLayoutParams();

image3dViewParams.width

=

-rightLayoutParams.rightMargin;

image3dView.setLayoutParams(image3dViewParams);

showImage3dView();

unFocusBindView();

}

@Override

protected

void

onPostExecute(Integer

rightMargin){

rightLayoutParams.rightMargin

=

rightMargin;

rightLayout.setLayoutParams(rightLayoutParams);

image3dView.setVisibility(INVISIBLE);

if

(isLeftLayoutVisible){

leftLayout

温馨提示

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

评论

0/150

提交评论