版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】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. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 银川2024年07版小学4年级上册英语第3单元测验卷
- 福州2024年10版小学英语第4单元测验卷
- 股骨颈骨折护理常规
- 2023年葡萄汁提取物化妆品投资申请报告
- 2024年质子交换膜燃料电池(REMFC)发电装置项目资金申请报告代可行性研究报告
- 模拟深海环境金属材料腐蚀-磨损耦合损伤评价方法
- 2021-2022学年人教版九年级化学上学期期中考试好题汇编:氧气(原卷版+解析)
- 美丽天津景点导游词(16篇)
- 诫子书读后感15篇
- 24.6 实数与向量相乘(第2课时)同步练习
- 电气工程施工应急预案
- 江苏省南通市如东高级中学2024-2025学年高二上学期期中考试数学试卷(含答案)
- 预防倾倒综合征
- 贸易安全内部培训教材
- 手术室急危重患者的抢救与配合
- 新能源汽车充电技术 课件 2-3 认知新能源汽车直流充电系统
- 2021年公务员国考《申论》真题(副省级)及参考答案(两套答案)
- 全国半导体行业职业技能竞赛(半导体芯片制造工赛项)理论考试题及答案
- 期末 (试题) -2024-2025学年人教PEP版(2024)英语三年级上册
- 2024 抖音直播知识考试题库200题(含答案)
- 护理案例教学法
评论
0/150
提交评论