快捷搜索:  as  test  1111  test aNd 8=8  test++aNd+8=8  as++aNd+8=8  as aNd 8=8

永乐国际旗舰厅app:Android实现推拉门式的立体特效滑动菜单



在上一篇文章中,我们进修了Camera的基础用法,并借助它们编写了一个例子,实现了类似于API Demos里的图片中轴扭转功能。不过那个例子的核心代码是来自于API Demos中带有的Rotate3dAnimation这个类,是它赞助我们完成了所有的三维扭转操作,所有Matrix和Camera相关的代码也是封装在这个类中。

这样说来的话,大年夜家心里会不会痒痒的呢?虽然进修了Camera的用法,但却没有按照自己的理解来实现一套异常炫酷的3D效果。不要发急,本日我就带着大年夜家一路来实现一种3D推拉门式的滑动菜单,而且完全不会借助任何API Demos里面的代码。

当然假如你还不是很懂得Camera的应用要领,可以先去涉猎我的上一篇文章 http://www.fengfly.com/plus/view-215100-1.html 。

关于滑动菜单的文章我也已经写过好几篇了,信托看过的同伙对滑动菜单的实现要领应该都已经对照认识了,那么本篇文章的重点就在于,若何在传统滑动菜单的根基上加入推拉门式的立体效果。还不懂得滑动菜单若何实现的同伙,可以去翻一翻我之前的文章。

下面照样回到正题,首先来讲一下此次的实现道理吧,着实传统的滑动菜单功能便是把菜单部分放在了下面,主结构放在了上面,然后根据手指滑动的间隔来偏移主结构,让菜单部分得以显示出来就行了。不过我们此次既然要做推拉门式的立体效果,就必要将传统的思维轻细转变一下,可以先让菜单部分暗藏掉落,但却复制一个菜单的镜像并天生一张图片,然后在手指滑动的时刻对这张图片进行三维操作,让它孕育发生推拉门式的效果,等滑动操作停止的时刻,才让真正的菜单显示出来,然后将这个图片暗藏。道理示意图如下所示:

那么下面我们就开始着手实现吧,首先新建一个Android项目,起名叫做ThreeDSlidingLayoutDemo。

然后新建一个Image3dView类承袭自View,用于天生镜像图片,以及完成三维操作,代码如下所示:

public class Image3dView extends View {

/**

* 源视图,用于天生图片工具。*/

private View sourceView;

/奸淫 根据传入的源视图天生的图片工具。

*/private Bitmap sourceBitmap;

/**

* 源视图的宽度。*/

private float sourceWidth;

/奸淫 Matrix工具,用于对图片进行矩阵操作。

*/private Matrix matrix = new Matrix();

/**

* Camera工具,用于对图片进行三维操作。*/

private Camera camera = new Camera();

/奸淫 Image3dView的构造函数

** @param context

* @param attrs*/

public Image3dView(Context context, AttributeSet attrs) {super(context, attrs);

}

/奸淫 供给外部接口,容许向Image3dView传入源视图。

** @param view

*传入的源视图*/

public void setSourceView(View view) {sourceView = view;

sourceWidth = sourceView.getWidth();}

/**

* 清除掉落缓存的图片工具。*/

public void clearSourceBitmap() {if (sourceBitmap != null) {

sourceBitmap = null;}

}

@Overrideprotected void onDraw(Canvas canvas) {

super.onDraw(canvas);if (sourceBitmap == null) {

getSourceBitmap();}

// 谋略图片必要扭转的角度float degree = 90 - (90 / sourceWidth) * getWidth();

camera.save();camera.rotateY(degree);

camera.getMatrix(matrix);camera.restore();

// 将扭转的中间点移动到屏幕左边缘的中心位置matrix.preTranslate(0, -getHeight() / 2);

matrix.postTranslate(0, getHeight() / 2);canvas.drawBitmap(sourceBitmap, matrix, null);

}

/奸淫 获取源视图对应的图片工具。

*/private void getSourceBitmap() {

if (sourceView != null) {sourceView.setDrawingCacheEnabled(true);

sourceView.layout(0, 0, sourceView.getWidth(), sourceView.getHeight());sourceView.buildDrawingCache();

sourceBitmap = sourceView.getDrawingCache();}

}

}

可以看到,Image3dView中供给了一个setSourceView()措施,用于通报源视图进来,我们稍后复制镜像便是对它进行复制。然后在onDraw()措施里对sourceBitmap进行判断,假如为空,则去调用getSourceBitmap()措施来天生一张镜像图片,getSourceBitmap()措施的细节大年夜家自己去看。在得到了镜像图片之后,接下来便是要谋略图片的扭转角度了,这里根据Image3dView当前的宽度和源视图的总宽度进行比较,按比例算出扭转的角度。然后调用Camera的rotateY()措施,让图片团练Y轴进行扭转,并将扭转的中间点移动到屏幕左边缘的中心位置,这几行代码我们在上篇文章中已经见过了,算是挺认识了吧!着末调用Canvas的drawBitmap()措施把图片绘制出来。

完成了Image3dView之后,接着我们要开始编写滑动菜单部分的代码,着实此次的代码和之前的滑动菜单代码大年夜同小异,看过我前面文章的同伙,此次理解起来必然会易如反掌。新建ThreeDSlidingLayout类,代码如下所示:

public class ThreeDSlidingLayout 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 = 永乐国际旗舰厅app0;

/奸淫 右侧结构最多可以滑动到的右边缘。

*/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;

/奸淫 重写SlidingLayout的构造函数,此中获取了屏幕的宽度。

** @param context

* @param attrs*/

public ThreeDSlidingLayout(Context context, AttributeSet attrs) {super(context, attrs);

WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);screenWidth = wm.getDefaultDisplay().getWidth();

touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();}

/**

* 绑定监听侧滑事故的View,即在绑定的View进行滑动才可以显示和暗藏左侧结构。*

* @param bindView*必要绑定的View工具。

*/public void setScrollEvent(View bindView) {

mBindView = bindView;mBindView.setOnTouchListener(this);

}

/奸淫 将屏幕滚动到左侧结构界面,滚动速率设定为10.

*/public void scrollToLeftLayout() {

image3dView.clearSourceBitmap();new ScrollTask().execute(-10);

}

/奸淫 将屏幕滚动到右侧结构界面,滚动速率设定为-10.

*/public void scrollToRightLayout() {

image3dView.clearSourceBitmap();new ScrollTask().execute(10);

}

/奸淫 左侧结构是否完全显示出来,或完全暗藏,滑动历程中此值无效。

** @return 左侧结构完全显示返回true,完全暗藏返回false。

*/public boolean isLeftLayoutVisible() {

return isLeftLayoutVisible;}

/**

* 在onLayout中从新设定左侧结构和右侧结构的参数。*/

@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {

super.onLayout(changed, l, t, r, b);if (changed && !loadOnce) {

// 获取左侧结构工具leftLayout = findViewById(R.id.menu);

leftLayoutParams = (MarginLayoutParams) leftLayout.getLayoutParams();rightEdge = -leftLayoutParams.width;

// 获取右侧结构工具rightLayout = findViewById(R.id.content);

rightLayoutParams = (MarginLayoutParams) rightLayout.getLayoutParams();rightLayoutParams.width = screenWidth;

rightLayout.setLayoutParams(rightLayoutParams);// 获取3D视图工具

image3dView = (Image3dView) findViewById(R.id.image_3d_view);// 将左侧结构传入3D视图中作为天生源

image3dView.setSourceView(leftLayout);loadOnce = true;

}}

@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;default:

break;}

} else if (upDistanceXscrollToRightLayout();

}recycleVelocityTracker();

break;}

if (v.isEnabled()) {if (isSliding) {

unFocusBindView();return true;

}if (isLeftLayoutVisible) {

return true;}

return false;}

return true;}

/**

* 履行滑动历程中的逻辑操作,如界限反省,改变偏移值,可见性反省等。*/

private void onSlide() {checkSlideBorder();

rightLayout.setLayoutParams(rightLayoutParams);image3dView.clearSourceBitmap();

image3dViewParams = image3dView.getLayoutParams();image3dViewParams.width = -rightLayoutParams.rightMargin;

// 滑动的同时改变3D视图的大年夜小image3dView.setLayoutParams(image3dViewParams);

// 包管在滑动历程中3D视图可见,左侧结构弗成见showImage3dView();

}

/奸淫 根据手指移动的间隔,判断当前用户的滑动意图,然后给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)

isSliding = true;slideState = SHOW_MENU;

}}

/**

* 在滑动历程中反省左侧菜单的界限值,防止绑定结构滑出屏幕。*/

private void checkSlideBorder() {if (rightLayoutParams.rightMargin > leftEdge) {

rightLayoutParams.rightMargin = leftEdge;} else if (rightLayoutParams.rightMargin

rightLayoutParams.rightMargin = rightEdge;}

}

/奸淫 判断是否应该滚动将左侧结构展示出来。假如手指移动间隔大年夜于屏幕的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;

}

/奸淫 创建VelocityTracker工具,并将触摸事故加入到VelocityTracker傍边。

** @param event

*右侧结构监听控件的滑动事故*/

private void createVelocityTracker(MotionEvent event) {if (mVelocityTracker == null) {

mVelocityTracker = VelocityTracker.obtain();}

mVelocityTracker.addMovement(event);}

/**

* 获取手指在右侧结构的监听View上的滑动速率。*

* @return 滑动速率,以每秒钟移动了若干像素值为单位。*/

private int getScrollVelocity() {mVelocityTracker.computeCurrentVelocity(1000);

int velocity = (int) mVelocityTracker.getXVelocity();return Math永乐国际旗舰厅app.abs(velocity);

}

/奸淫 收受接收VelocityTracker工具。

*/private void recycleVelocityTracker() {

mVelocityTracker.recycle();mVelocityTracker = null;

}

/奸淫 应用可以得到焦点的控件在滑动的时刻掉去焦点。

*/private void unFocusBindView() {

if (mBindView != null) {mBindView.setPressed(false);

mBindView.setFocusable(false);mBindView.setFocusableInTouchMode(false);

}}

/**

* 包管此时让左侧结构弗成见,3D视图可见,从而让滑动历程中孕育发生3D的效果。*/

private void showImag永乐国际旗舰厅appe3dView() {if (image3dView.getVisibility() != View.VISIBLE) {

image3dView.setVisibility(View.VISIBLE);}

if (leftLayout.getVisibility() != View.INVISIBLE) {leftLayout.setVisibility(View.INVISIBLE);

}}

class ScrollTask extends AsyncTask {

@Override

protected Integer doInBackground(Integer... speed) {int rightMargin = rightLayoutParams.rightMargin;

// 根据传入的速率来滚动界面,当滚动到达左界限或右界限时,跳出轮回。while (true) {

rightMargin = rightMargin + speed[0];if (rightMargin

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;

}

@Overrideprotected 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);image3dViewParams = image3dView.getLayoutParams();

image3dViewParams.width = -rightLayoutParams.rightMargin;image3dView.setLayoutParams(image3dViewParams);

if (isLeftLayoutVisible) {// 包管在滑动停止后左侧结构可见,3D视图弗成见。

image3dView.setVisibility(View.INVISIBLE);leftLayout.setVisibility(View.VISIBLE);

}}

}

/奸淫 使当火线程就寝指定的毫秒数。

** @param millis

*指定当火线程就寝多久,以毫秒为单位*/

private void sleep(long millis) {try {

Thread.sleep(millis);} catch (InterruptedException e) {

e.printStackTrace();}

}}

代码对照长,我照样带着大年夜家来理一下思路。首先在onLayout措施中,我们分手初始化了左侧结构工具、右侧结构工具和Image3dView工具,这三个工具稍后都要设置设置设备摆设摆设到Activity结构里面的。在onLayout()措施的着末,调用了Image3dView的setSourceView()措施,并将左侧结构工具传了进去,阐明我们后面就要对它进行镜像复制。

当手指在界面上拖动来显示左侧结构的时刻,就会进入到onTouch()措施中,这里会调用checkSlideState()措施来反省滑动的状态,以判断用户是想要显示左侧结构照样暗藏左侧结构,然后根据手指滑动的间隔对右侧结构进行偏移,就可以实现基础的滑动效果了。接下来是重点内容,这里会根据右侧结构的偏移量来改变Image3dView的宽度,当Image3dView大年夜小发生改变时,当然会调用onDraw()措施来进行重绘,此时我们编写的三维扭转逻辑就可以获得履行了,于是就会孕育发生立体的推拉门式效果。留意,在全部的滑动历程中,真正的左侧结构不停都是弗成见的,我们所看到的只是它的一张镜像图片。

当手指脱离屏幕后,会根据当前的移动间隔来抉择是显示左侧结构照样暗藏左侧结构,并会调用scrollToLeftLayout()措施或scrollToRightLayout()措施来完成后续的滚动操作。当全部滚动操作完成之后,才会将真正的左侧结构显示出来,再把镜像图片暗藏掉落,这样用户就可以点击左侧结构上按钮之类的器械了。

接着我们必要在Activity的结构文件傍边去引用这个三维滑动菜单框架,打开或新建activity_main.xml作为法度榜样的主结构文件,代码如下所示:

com.example.slidinglayout3d.ThreeDSlidingLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"android:id="@+id/slidingLayout"

android:layout_width="fill_parent"android:layout_height="fill_parent" >

RelativeLayout

android:id="@+id/menu"android:layout_width="270dip"

android:layout_height="fill_parent"android:layout_alignParentLeft="true"

android永乐国际旗舰厅app:background="#00ccff"android:visibility="invisible" >

LinearLayout

android:layout_width="match_parent"android:layout_height="wrap_content"

android:layout_centerInParent="true"android:orientation="vertical" >

TextView

android:layout_width="wrap_content"android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"android:text="This is menu"

android:textColor="#000000"android:textSize="28sp" />

Button

android:layout_width="wrap_content"android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"android:text="Test Button" />

LinearLayout>RelativeLayout>

LinearLayout

android:id="@+id/content"android:layout_width="320dip"

android:layout_height="fill_parent"android:layout_alignParentRight="true"

android:background="#e9e9e9"android:orientation="vertical"

android:visibility="vi永乐国际旗舰厅appsible" >

Buttonandroid:id="@+id/menuButton"

android:layout_width="wrap_content"android:layout_height="wrap_content"

android:text="Menu" />

ListViewandroid:id="@+id/contentList"

android:layout_width="fill_parent"android:layout_height="fill_parent"

android:cacheColorHint="#00000000" >ListView>

LinearLayout>

com.example.slidinglayout3d.Image3dViewandroid:id="@+id/image_3d_view"

android:layout_width="wrap_content"android:layout_height="wrap_content"

android:layout_alignParentLeft="true"android:visibility="invisible" />

com.example.slidinglayout3d.ThreeDSlidingLayout>

可以看到,在最外层的ThreeDSlidingLayout结构里面,我们放入了三个直接子结构,第一个RelativeLayout也便是左侧结构了,里面简单地放了一个TextView和一个按钮。第二个LinearLayout是右侧结构,里面放入了一个按钮和一个ListView,都是用于显示左侧结构而筹备的。第三个是Image3dView,当然是用于在滑动历程中显示左侧结构的镜像图片了。

着末,打开或新建MainActivity作为法度榜样的主Activity,在里面加入如下代码:

public class MainActivity extends Activity {

/**

* 侧滑结构工具,用于经由过程手指滑动将左侧的菜单结构进行显示或暗藏。*/

private ThreeDSlidingLayout slidingLayout;

/奸淫 menu按钮,点击按钮展示左侧结构,再点击一次暗藏左侧结构。

*/private Button menuButton;

/**

* 放在content结构中的ListView。*/

private ListView contentListView;

/奸淫 感化于contentListView的适配器。

*/private ArrayAdapter contentListAdapter;

/**

* 用于添补contentListAdapter的数据源。*/

private String[] contentItems = { "Content Item 1", "Content Item 2", "Content Item 3","Content Item 4", "Content Item 5", "Content Item 6", "Content Item 7",

"Content Item 8", "Content Item 9", "Content Item 10", "Content Item 11","Content Item 12", "Content Item 13", "Content Item 14", "Content Item 15",

"Content Item 16" };

@Overrideprotected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

slidingLayout = (ThreeDSlidingLayout) findViewById(R.id.slidingLayout);menuButton = (Button) findViewById(R.id.menuButton);

contentListView = (ListView) findViewById(R.id.contentList);contentListAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1,

contentItems);contentListView.setAdapter(contentListAdapter);

// 将监听滑动事故绑定在contentListView上slidingLayout.setScrollEvent(contentListView);

menuButton.setOnClickListener(new OnClickListener() {@Override

public void onClick(View v) {if (slidingLayout.isLeftLayoutVisible()) {

slidingLayout.scrollToRightLayout();} else {

slidingLayout.scrollToLeftLayout();}

}});

contentListView.setOnItemClickListener(new OnItemClickListener() {@Override

public void onItemClick(AdapterView parent, View view, int position, long id) {String text = contentItems[position];

Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();}

});}

}

这些代码应该都异常简单和眼熟了吧,和曩昔滑动菜单中的代码完全一样,调用ThreeDSlidingLayout的setScrollEvent措施,将ListView作为绑定结构传入,这样就可以经由过程拖动ListView来显示或暗藏左侧结构。并且在按钮的点击事故里也加入了显示和暗藏左侧结构的逻辑。

好了,这样所有的编码事情就已经完成了,让我们来运行一下吧,效果如下图所示:

怎么样?效果异常炫丽吧!着实只要对Camera进行奇妙地运用,还可以编写出很多异常杰出的殊效,就看你敢不敢去发挥你的想象力了。

源码下载,请点击这里

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

您可能还会对下面的文章感兴趣: