在上一篇文章《Android自己定义组件系列【3】——自己定义ViewGroup实现側滑》中实现了仿Facebook和人人网的側滑效果,这一篇我们将接着上一篇来实现双面滑动的效果。

1、布局示意图:


2、核心代码

  @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = MeasureSpec.getSize(widthMeasureSpec);  //获取MyScrollView的宽度mHeight = MeasureSpec.getSize(heightMeasureSpec); //获取MyScrollView的高度if(!isLocked){initX = getScrollX();isLocked = true;}}

在该方法中获取到初始的视图坐标偏移量getScrollX()

   @Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:System.out.println("ACTION_DOWN");mDownX = x;          //记录按下时的x坐标break;case MotionEvent.ACTION_UP:System.out.println("ACTION_UP");int dis = (int) (x - mDownX);   //滑动的距离if(Math.abs(dis) > (mWidth * mMenuWeight / 2)){if(dis > 0){          //假设>0则是向右滑动toRightMove();}else{                 //假设<0则是向左滑动toLeftMove();}}break;default:break;}return true;}

监听函数记录下按下和移动的屏幕坐标。求差计算出移动距离,假设这个距离大于阀值 (mWidth * mMenuWeight / 2)则滑动

 public void toRightMove(){System.out.println("maxRight = " + maxRight);System.out.println("X = "  + getScrollX());if(getScrollX() >= initX){int dx = (int)(mWidth * mMenuWeight);mScroller.startScroll(getScrollX(), 0, -dx, 0, 500);if(mListener != null){mListener.onChanged();}invalidate();}}

假设是向右滑动则。假设当前是初始位置(centerView在中间)则能够向右滑动(getScrollX == initX),或者当前左边View能够看见,则能够向右滑动将centerView移动到中间(getScrollX > initX).同理有向左滑动的方法。

    public void toLeftMove(){System.out.println("maxLeft = " + maxLeft);System.out.println("X = "  + getScrollX());if(getScrollX() <= initX){int dx = (int)(mWidth * mMenuWeight);mScroller.startScroll(getScrollX(), 0, dx, 0, 500);if(mListener != null){mListener.onChanged();}invalidate();}}

3、所有代码

MyScrollView.java

package com.example.testscrollto;import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Scroller;public class MyScrollView extends LinearLayout{private Context mContext;private int mWidth;private int mHeight;private float mMenuWeight = 3.0f / 5; //菜单界面比例private View mMenuView;   //菜单界面private View mPriView;   //内容界面private View mRightView;  //右边界面private int maxLeft;private int maxRight;private int initX;private boolean isLocked = false;private Scroller mScroller;private OnMenuChangedListener mListener;public MyScrollView(Context context, AttributeSet attrs) {super(context, attrs);mContext = context;mScroller = new Scroller(mContext);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);mMenuView.layout(-(int)(mWidth * mMenuWeight), 0, 0, mHeight);mPriView.layout(0, 0, mWidth, mHeight);mRightView.layout(mWidth, 0, mWidth + (int)(mWidth * mMenuWeight), mHeight);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = MeasureSpec.getSize(widthMeasureSpec);  //获取MyScrollView的宽度mHeight = MeasureSpec.getSize(heightMeasureSpec); //获取MyScrollView的高度if(!isLocked){initX = getScrollX();isLocked = true;}}/**设置右滑的菜单View*/public void setMenu(View menu){mMenuView = menu;addView(mMenuView);}/*** 设置主界面View*/public void setPrimary(View primary){mPriView = primary;addView(mPriView);}public void setRightView(View rightview){mRightView = rightview;addView(mRightView);}private float mDownX;@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:System.out.println("ACTION_DOWN");mDownX = x;          //记录按下时的x坐标break;case MotionEvent.ACTION_UP:System.out.println("ACTION_UP");int dis = (int) (x - mDownX);   //滑动的距离if(Math.abs(dis) > (mWidth * mMenuWeight / 2)){if(dis > 0){          //假设>0则是向右滑动toRightMove();}else{                 //假设<0则是向左滑动toLeftMove();}}break;default:break;}return true;}@Overridepublic void computeScroll() {super.computeScroll();if(mScroller.computeScrollOffset()){scrollTo(mScroller.getCurrX(), mScroller.getCurrY());postInvalidate();}}public void toRightMove(){System.out.println("maxRight = " + maxRight);System.out.println("X = "  + getScrollX());if(getScrollX() >= initX){int dx = (int)(mWidth * mMenuWeight);mScroller.startScroll(getScrollX(), 0, -dx, 0, 500);if(mListener != null){mListener.onChanged();}invalidate();}}public void toLeftMove(){System.out.println("maxLeft = " + maxLeft);System.out.println("X = "  + getScrollX());if(getScrollX() <= initX){int dx = (int)(mWidth * mMenuWeight);mScroller.startScroll(getScrollX(), 0, dx, 0, 500);if(mListener != null){mListener.onChanged();}invalidate();}}public interface OnMenuChangedListener{public void onChanged();}   public void setOnMenuChangedListener(OnMenuChangedListener listener){mListener = listener;}
}

MainActivity.java

package com.example.testscrollto;import android.app.Activity;
import android.os.Bundle;
import android.view.View;import com.example.testscrollto.MyScrollView.OnMenuChangedListener;public class MainActivity extends Activity {private MyScrollView mScrollView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mScrollView = (MyScrollView)findViewById(R.id.rightscrollview);final View menu = getLayoutInflater().inflate(R.layout.rightscrollview_menu, null);final View primary = getLayoutInflater().inflate(R.layout.rightscrollview_primary, null);final View rightview = getLayoutInflater().inflate(R.layout.rightscrollview_right_menu, null);mScrollView.setMenu(menu);mScrollView.setPrimary(primary);mScrollView.setRightView(rightview);mScrollView.setOnMenuChangedListener(new OnMenuChangedListener() {@Overridepublic void onChanged() {System.out.println("窗体切换了一次");}});}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><com.example.testscrollto.MyScrollViewandroid:id="@+id/rightscrollview"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>

其余三个视图界面无限制。能够自由定义,这里就不贴出来了。


4、执行效果:


源码下载:http://download.csdn.net/detail/lxq_xsyu/7232701

这样就能够实现左右滑动了,没有不论什么bug吗?

事实上这样看似是没有什么问题了,上面用于推断界面位置的代码在逻辑上看似是对的,可是在实际的应用中偶尔会出现错乱。

以下我们用第二种方式解决:

package com.example.jaohangui.view;import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Scroller;public class MyScrollLeftRightView extends LinearLayout{private Scroller mScroller;private View mLeftView;  //坐标界面private View mMainView;  //中间主界面private View mRightView; //右边界面private float mMeasureWight = 3.0f / 5; //菜单界面比例private int mWidth;    private int mHeight;private boolean isLocked = false;private boolean isToLeft = false;private static int CENTER_PAGE = 1;private static int LEFT_PAGE = 0;private static int RIGHT_PAGE = 2;private int currentPage = CENTER_PAGE;public MyScrollLeftRightView(Context context, AttributeSet attrs) {super(context, attrs);mScroller = new Scroller(context);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);mLeftView.layout(-(int)(mWidth * mMeasureWight), 0, 0, mHeight);mMainView.layout(0, 0, mWidth, mHeight);mRightView.layout(mWidth, 0, mWidth + (int)(mWidth * mMeasureWight), mHeight);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = MeasureSpec.getSize(widthMeasureSpec);mHeight = MeasureSpec.getSize(heightMeasureSpec);}/*** 加入左边界面内容* @param view*/public void setLeftView(View view){mLeftView = view;addView(mLeftView);}/*** 加入主界面内容* @param view*/public void setMainView(View view){mMainView = view;addView(mMainView);}/*** 加入右边界面内容* @param view*/public void setRightView(View view){mRightView = view;addView(mRightView);}private float mDownX;@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mDownX = x;break;case MotionEvent.ACTION_UP:int dis = (int)(x - mDownX); //滑动的距离if(Math.abs(dis) > (mWidth * mMeasureWight / 3)){if(dis > 0){toRightMove();}else{toLeftMove();}}break;default:break;}return true;}@Overridepublic void computeScroll() {super.computeScroll();if(mScroller.computeScrollOffset()){isLocked = true;scrollTo(mScroller.getCurrX(), mScroller.getCurrY());postInvalidate();}else{if(currentPage == CENTER_PAGE){if(isToLeft){currentPage = RIGHT_PAGE;}else{currentPage = LEFT_PAGE;}}else{currentPage = CENTER_PAGE;}isLocked = false;}}public void toRightMove(){if(currentPage == LEFT_PAGE || isLocked){return;}int dx = (int)(mWidth * mMeasureWight);mScroller.startScroll(getScrollX(), 0, -dx, 0, 500);invalidate();isToLeft = false;}public void toLeftMove(){if(currentPage == RIGHT_PAGE || isLocked){return;}System.out.println("ok");int dx = (int)(mWidth * mMeasureWight);mScroller.startScroll(getScrollX(), 0, dx, 0, 500);invalidate();isToLeft = true;}
}

上面使用了两个用来推断的变量和一个锁定状态(不让进入toLeftMove和toRightMove)的变量。

1、在进入toLeftMove或者toRightMove方法的时候首先会推断是否isLocked为true,假设为true则说明当前是正在滑动状态,不能够执行这两个方法。假设不这样去控制。在界面正在滑动的时候上面的currentPage就会发生错乱。

2、将要滑动之前告诉computeScroll()方法,是从toLeftMove和toRightMove的那个方法中出来的(使用isToLeft)。

3、最后推断Scroller是否已经停止滑动(移动),假设停止则改变当前页面的状态(currentPage的值)

有的时候我们尽管实现了一个功能或者某个逻辑,而怎样才干使这段代码更加健壮和有效更值得我们去认真思考。

。。

Android自己定义组件系列【4】——自己定义ViewGroup实现双側滑动相关推荐

  1. Android自己定义组件系列【6】——进阶实践(3)

    上一篇<Android自己定义组件系列[5]--进阶实践(2)>继续对任老师的<可下拉的PinnedHeaderExpandableListView的实现>进行了分析,这一篇计 ...

  2. Android自己定义组件系列【2】——Scroller类

    在上一篇中介绍了View类的scrollTo和scrollBy两个方法,对这两个方法不太了解的朋友能够先看<自己定义View及ViewGroup> scrollTo和scrollBy尽管实 ...

  3. Android深入四大组件(六)Android8.0 根Activity启动过程(前篇)

    相关文章 Android深入四大组件系列 Android系统启动系列 Android应用程序进程系列 Android深入解析AMS系列 前言 在几个月前我写了Android深入四大组件(一)应用程序启 ...

  4. Android深入四大组件(七)Android8.0 根Activity启动过程(后篇)

    相关文章 Android深入四大组件系列 Android系统启动系列 Android应用程序进程系列 Android深入解析AMS系列 前言 在几个月前我写了Android深入四大组件(一)应用程序启 ...

  5. 【Android 组件化】使用 Gradle 实现组件化 ( Gradle 变量定义与使用 )

    文章目录 一.顶层 Gradle 定义扩展变量 二.获取顶层的 Gradle 对象 三.Module 中使用 Gradle 变量 四.Gradle 中打印变量值 五.涉及到的 Gradle 构建脚本 ...

  6. 【愚公系列】2022年10月 微信小程序-优购电商项目-⾃定义组件传参

    文章目录 前言 一.id和data-xxx传参 二.导航传值 三.父子组件传值 前言 组件传参是小程序中非常重要的一个功能,因为小程序大多都是组件形式存在的. 一.id和data-xxx传参 view ...

  7. Xamarin Android提示找不到资源属性定义

    Xamarin Android提示找不到资源属性定义 错误信息:"Resource.Attribute"未包含"actonBarSize"的定义 Xamarin ...

  8. 实例演示使用RDIFramework.NET 框架的工作流组件进行业务流程的定义—请假申请流程-Web

    实例演示使用RDIFramework.NET 框架的工作流组件 进行业务流程的定义-请假申请流程-Web 参考文章: RDIFramework.NET - 基于.NET的快速信息化系统开发框架 - 系 ...

  9. 实例演示使用RDIFramework.NET 框架的工作流组件进行业务流程的定义—请假申请流程-WinForm

    实例演示使用RDIFramework.NET 框架的工作流组件 进行业务流程的定义-请假申请流程-WinForm 参考文章: RDIFramework.NET - 基于.NET的快速信息化系统开发框架 ...

最新文章

  1. 第十六届全国大学生智能车竞赛比赛获奖证书格式说明以及下载链接
  2. Fully Convolutional Networks for semantic Segmentation(深度学习经典论文翻译)
  3. html显示高亮c++
  4. 计算机技能大赛图形试题,图形图像处理技能大赛竞赛试题试卷.doc
  5. vue ----组件数据共享
  6. mybatis的mysql参数传递_Mybatis参数传递及返回类型
  7. 史陶比尔staubli机器人手柄控制器维修操作屏修理
  8. 【Word】编号与文字间距过大
  9. UCOSIII---工程移植
  10. 层次分析法的缺点和改进
  11. 初探Flowable流程引擎,偶遇多实例子流程
  12. 伦敦 quant_伦敦统一用户组(LUUG)见面v2.0
  13. 计算机学院肖鹏,肖鹏-重庆大学物理学院
  14. 做数据挖掘工作需要具备哪些思维原理?
  15. Leap Motion 之Unity 开发实战(一. 制作手的HandController)
  16. 联发科技嵌入式_【MTK联发科技嵌入式驱动工程师面试】面试官人很好,问的问题很基础。-看准网...
  17. Pyqt5 pandas matplotlib network自用操作
  18. gitlab下载安装使用,rpm包
  19. 2021年熔化焊接与热切割复审考试及熔化焊接与热切割作业模拟考试
  20. 千里之行始于足下 开始篇

热门文章

  1. mysql 全连接查询合并字段
  2. Vue2.x通用条件搜索组件的封装及应用
  3. End to End Sequence Labeling via Bi-directional LSTM CNNs CRF
  4. 安卓代码迁移:Program sh not found in PATH
  5. 图像的全局特征--LBP特征
  6. python变量后面加星号_Python开发中关于参数使用的几点建议 -- 1
  7. 深入理解Java虚拟机(类文件结构)
  8. containerd项目正式从CNCF毕业
  9. python练习笔记——分解质因数
  10. 从微软的DBML文件中我们能学到什么(它告诉了我们什么是微软的重中之重)~四 分部方法从另一方面定义了类型的操作规范...