Android自定义组件——四个方向滑动的菜单实现
今天无意中实现了一个四个方向滑动的菜单,感觉挺好玩,滑动起来很顺手,既然已经做出来了就贴出来让大家也玩弄一下。
一、效果演示
(说明:目前没有安装Android模拟器,制作的动态图片太卡了,就贴一下静态图片吧,实际效果可以下载源代码查看)
(向上滑动)
(向下滑动)
(向左滑动)
(向右滑动)
二、实现过程介绍
1、放置5个View (分别是上下左右中)
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- mTopView.layout(0, -mViewHeight, mViewWidth, 0);
- mBottomView.layout(0, mViewHeight, mViewWidth, 2 * mViewHeight);
- mCenterView.layout(0, 0, mViewWidth, mViewHeight);
- mLeftView.layout(-mViewWidth, 0, 0, mViewHeight);
- mRightView.layout(mViewWidth, 0, 2 * mViewWidth, mViewHeight);
- }
转载请说明出处:http://blog.csdn.net/dawanganban
2、通过onTouchEvent事件来判断移动方向
- private float mDownY;
- private float mDownX;
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- int disY;
- int disX;
- float eventY = event.getY();
- float eventX = event.getX();
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mDownY = eventY;
- mDownX = eventX;
- break;
- case MotionEvent.ACTION_UP:
- disY = (int)(eventY - mDownY);
- disX = (int)(eventX - mDownX);
- if(Math.abs(disY) > Math.abs(disX)){
- if(Math.abs(disY) > MIN_VIEW_HEIGHT / 2){
- if(disY > 0){ //向下滑动
- Log.d(TAG, "TO_BOTTOM");
- changeToBottom();
- }else{ //向上滑动
- Log.d(TAG, "TO_TOP");
- changeToTop();
- }
- }
- }else{
- if(Math.abs(disX) > MIN_VIEW_WIDTH / 2){
- if(disX > 0){ //向右滑动
- Log.d(TAG, "TO_RIGHT");
- changeToRight();
- }else{ //向左滑动
- Log.d(TAG, "TO_LEFT");
- changeToLeft();
- }
- }
- }
- break;
- default:
- break;
- }
- return true;
- }
3、通过computerScroll()方法实现平滑移动
- @Override
- public void computeScroll() {
- super.computeScroll();
- if(mScroller.computeScrollOffset()){
- scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
- postInvalidate();
- }
- }
4、判断临界条件(否则会一直向一个方向滑动)
- int[] location = new int[2];
- mCenterView.getLocationOnScreen(location);
- if(location[1] >= mViewHeight - MIN_VIEW_HEIGHT * 2) return;
例如上面代码就是判断向下滑动的临界条件,location[1]代表中间View的y坐标(相对于屏幕)。
三、整个View的源码
- package com.example.testmx4update;
- import android.content.Context;
- import android.graphics.Color;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.Scroller;
- /**
- * 自定义可以拖动的View
- * @author 阳光小强 http://blog.csdn.net/dawanganban
- *
- */
- public class MyCanPullView extends ViewGroup{
- private static final int MIN_VIEW_HEIGHT = 200;
- private static final int MIN_VIEW_WIDTH = 400;
- private static final String TAG = "TEST";
- private int mViewHeight;
- private int mViewWidth;
- private View mTopView;
- private View mBottomView;
- private View mCenterView;
- private View mLeftView;
- private View mRightView;
- private Scroller mScroller;
- public MyCanPullView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initView(context);
- mScroller = new Scroller(context);
- }
- private void initView(Context context) {
- setTopView(context);
- setBottomView(context);
- setCenterView(context);
- setLeftView(context);
- setRightView(context);
- }
- private float mDownY;
- private float mDownX;
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- int disY;
- int disX;
- float eventY = event.getY();
- float eventX = event.getX();
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mDownY = eventY;
- mDownX = eventX;
- break;
- case MotionEvent.ACTION_UP:
- disY = (int)(eventY - mDownY);
- disX = (int)(eventX - mDownX);
- if(Math.abs(disY) > Math.abs(disX)){
- if(Math.abs(disY) > MIN_VIEW_HEIGHT / 2){
- if(disY > 0){ //向下滑动
- Log.d(TAG, "TO_BOTTOM");
- changeToBottom();
- }else{ //向上滑动
- Log.d(TAG, "TO_TOP");
- changeToTop();
- }
- }
- }else{
- if(Math.abs(disX) > MIN_VIEW_WIDTH / 2){
- if(disX > 0){ //向右滑动
- Log.d(TAG, "TO_RIGHT");
- changeToRight();
- }else{ //向左滑动
- Log.d(TAG, "TO_LEFT");
- changeToLeft();
- }
- }
- }
- break;
- default:
- break;
- }
- return true;
- }
- private void changeToBottom(){
- int[] location = new int[2];
- mCenterView.getLocationOnScreen(location);
- if(location[1] >= mViewHeight - MIN_VIEW_HEIGHT * 2) return;
- int dy = (int)(mViewHeight - MIN_VIEW_HEIGHT);
- mScroller.startScroll(0, getScrollY(), 0, -dy, 500);
- invalidate();
- }
- private void changeToTop(){
- int[] location = new int[2];
- mTopView.getLocationOnScreen(location);
- if(location[1] <= -mViewHeight - MIN_VIEW_HEIGHT / 2) return;
- int dy = (int)(mViewHeight - MIN_VIEW_HEIGHT);
- mScroller.startScroll(0, getScrollY(), 0, dy, 500);
- invalidate();
- }
- private void changeToRight(){
- int[] location = new int[2];
- mCenterView.getLocationOnScreen(location);
- if(location[0] >= mViewWidth - MIN_VIEW_WIDTH * 2) return;
- int dx = (int)(mViewWidth - MIN_VIEW_WIDTH);
- mScroller.startScroll(getScrollX(), 0, -dx, 0, 500);
- invalidate();
- }
- private void changeToLeft(){
- Log.d(TAG, "TO_LEFT");
- int[] location = new int[2];
- mLeftView.getLocationOnScreen(location);
- if(location[0] <= -mViewWidth - MIN_VIEW_WIDTH / 2) return;
- int dx = (int)(mViewWidth - MIN_VIEW_WIDTH);
- mScroller.startScroll(getScrollX(), 0, dx, 0, 500);
- invalidate();
- }
- @Override
- public void computeScroll() {
- super.computeScroll();
- if(mScroller.computeScrollOffset()){
- scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
- postInvalidate();
- }
- }
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- mTopView.layout(0, -mViewHeight, mViewWidth, 0);
- mBottomView.layout(0, mViewHeight, mViewWidth, 2 * mViewHeight);
- mCenterView.layout(0, 0, mViewWidth, mViewHeight);
- mLeftView.layout(-mViewWidth, 0, 0, mViewHeight);
- mRightView.layout(mViewWidth, 0, 2 * mViewWidth, mViewHeight);
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- //获取整个View的宽高
- mViewWidth = MeasureSpec.getSize(widthMeasureSpec);
- mViewHeight = MeasureSpec.getSize(heightMeasureSpec);
- }
- private void setTopView(Context context){
- View topButton = new View(context);
- topButton.setBackgroundColor(Color.RED);
- mTopView = topButton;
- this.addView(mTopView);
- }
- private void setBottomView(Context context){
- View bottomButton = new View(context);
- bottomButton.setBackgroundColor(Color.GREEN);
- mBottomView = bottomButton;
- this.addView(mBottomView);
- }
- private void setCenterView(Context context){
- View centerButton = new View(context);
- centerButton.setBackgroundColor(Color.WHITE);
- mCenterView = centerButton;
- this.addView(mCenterView);
- }
- private void setLeftView(Context context){
- View leftButton = new View(context);
- leftButton.setBackgroundColor(Color.BLUE);
- mLeftView = leftButton;
- this.addView(mLeftView);
- }
- private void setRightView(Context context){
- View rightButton = new View(context);
- rightButton.setBackgroundColor(Color.YELLOW);
- mRightView = rightButton;
- this.addView(mRightView);
- }
- }
获取全部源代码,请加群在群共享中获取(142979499)
Android自定义组件——四个方向滑动的菜单实现的更多相关文章
- Android自定义组件系列【15】——四个方向滑动的菜单实现
今天无意中实现了一个四个方向滑动的菜单,感觉挺好玩,滑动起来很顺手,既然已经做出来了就贴出来让大家也玩弄一下. 一.效果演示 (说明:目前没有安装Android模拟器,制作的动态图片太卡了,就贴一下静 ...
- Android自定义组件系列【4】——自定义ViewGroup实现双侧滑动
在上一篇文章<Android自定义组件系列[3]--自定义ViewGroup实现侧滑>中实现了仿Facebook和人人网的侧滑效果,这一篇我们将接着上一篇来实现双面滑动的效果. 1.布局示 ...
- Android自定义组件系列【7】——进阶实践(4)
上一篇<Android自定义组件系列[6]--进阶实践(3)>中补充了关于Android中事件分发的过程知识,这一篇我们接着来分析任老师的<可下拉的PinnedHeaderExpan ...
- Android自定义视图四:定制onMeasure强制显示为方形
这个系列是老外写的,干货!翻译出来一起学习.如有不妥,不吝赐教! Android自定义视图一:扩展现有的视图,添加新的XML属性 Android自定义视图二:如何绘制内容 Android自定义视图三: ...
- Android自定义组件之自动换行及宽度自适应View:WordWrapView
目的: 自定义一个ViewGroup,里面的子view都是TextView,每个子view TextView的宽度随内容自适应且每行的子View的个数自适应,并可以自动换行 一:效果图 二:代码 整 ...
- Android自定义组件系列【5】——进阶实践(2)
上一篇<Android自定义组件系列[5]--进阶实践(1)>中对任老师的<可下拉的PinnedHeaderExpandableListView的实现>前一部分进行了实现,这一 ...
- Android自定义组件系列【6】——进阶实践(3)
上一篇<Android自定义组件系列[5]--进阶实践(2)>继续对任老师的<可下拉的PinnedHeaderExpandableListView的实现>进行了分析,这一篇计划 ...
- Android自定义组件系列【3】——自定义ViewGroup实现侧滑
有关自定义ViewGroup的文章已经很多了,我为什么写这篇文章,对于初学者或者对自定义组件比较生疏的朋友虽然可以拿来主义的用了,但是要一步一步的实现和了解其中的过程和原理才能真真脱离别人的代码,举一 ...
- Android 自定义组件之如何实现自定义组件
参考链接:http://blog.csdn.net/jjwwmlp456/article/details/41076699 简介 Android提供了用于构建UI的强大的组件模型.两个基类:View和 ...
随机推荐
- ELK filter过滤器来收集Nginx日志
前面已经有ELK-Redis的安装,此处只讲在不改变日志格式的情况下收集Nginx日志. 1.Nginx端的日志格式设置如下: log_format access '$remote_addr - $r ...
- c#基础操作
内网 IPAddress ipAddr = Dns.Resolve(Dns.GetHostName()).AddressList[];//获得当前IP地址 string ip = ipAddr.ToS ...
- Sql Server查询视图和表
SELECT obj.name tablename, CAST ( CASE WHEN (SELECT COUNT() FROM sys.indexes WHERE object_id= obj.OB ...
- springBoot配置文件application.properties
# =================================================================== # COMMON SPRING BOOT PROPERTIE ...
- Yii2.0 to(), toRoute(), current()区别用法
[Url::current] - 现在测试本地路径(http://daxia.dc.weixin.com/mobile/hmConnections/user/verify-user) a: //获取当 ...
- Yii2 session的使用方法(3)
Flash数据是一种特别的session数据,它一旦在某个请求中设置后, 只会在下次请求中有效,然后该数据就会自动被删除. 常用于实现只需显示给终端用户一次的信息, 如用户提交一个表单后显示确认信息. ...
- SOA及分布式
结合领域驱动设计的SOA分布式软件架构 Windows平台分布式架构实践 - 负载均衡(下) 分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架,附代码下载 我终于深入参与了一 ...
- js requestAnimationFrame
requestAnimationFrame,Web中写动画的另一种选择 原文:https://www.cnblogs.com/Wayou/p/requestAnimationFrame.html H ...
- [译]Angular-ui 之 Url Routing
◄ 前一篇 (Multiple Named Views) 下一篇 (The Components) ► 在你的应用中多数的状态都是基于特定的url地址的.Url Routing机制绝不是在状态 ...
- 【WP8】扩展CM的INavigationService方法
CM支持通过ViewModel进行导航,并通过支持参数传递,但是内部只是通过反射的方式构造Uri的参数进行导航,所以只支持简单类型的参数传递,下面对其进行扩展,在页面导航时支持复杂类型的参数传递,并扩 ...