转载请注明出处:王亟亟的大牛之路

开场白惯用鼓励诗句:

黑发不知勤学早,白首方悔读书迟。 —— 颜真卿《劝学诗》

这一系列的博文这是第五篇了,感谢大家的支持以及陪伴,往后我也会继续努力写出高质量的内容,谢谢

今天上的是一个自定义View,新鲜出炉,先上下效果(是一张张截图拼接的Gif动画都看不出来了,大家理解就行可以下Demo跑)

样例分析(最简单的描述了)

黑色线条是我们的手机

红色是我们自定义的”TitleBar”

蓝色是我们的自定义布局

紫色是自定义布局填充的内容

我们只需要配置我们蓝色内容的参数就可以对动画效果以及大小等进行设置。
PS:因为 蓝色内容吃掉了所有蓝色区域的OnTouch,所以紫色就不要做用户交互内容了,纯粹做展示吧TOT(小的该死)

看下项目结构:

就比上次的代码多了一些资源文件和4个类,一个就是我们的麦麦Activity,另外3个解释下

DraggableFlipView我们的自定义控件

DragGestureDetector我们的触碰效果处理类

FlipListener动作展示以及处理结果

OK,开始分析

DraggableFlipView

public class DraggableFlipView extends FrameLayout implements DragGestureDetector.DragGestureListener {//一系列的声明,不一一解释了,后面用到了会加以解释private static final float DRAG_THRESHOLD_PARAM = 50.0f;private static final int DEFAULT_VALUE = 0;private static final int DEFAULT_DRAGGABLE_VALUE = 50;private static final int DEFAULT_DRAG_DETECT_VALUE = 7;private DragGestureDetector mDragGestureDetector;private boolean isAnimation;private boolean isDragging;private int mAngle;private int mDraggableAngle;private int mDragDetectAngle;private boolean mIsReverse;private FlipListener mFlipListener;private RelativeLayout mFrontLayout;private RelativeLayout mBackLayout;//声明左右状态的枚举private enum RotateDirection {RIGHT(1), LEFT(-1);private int mValue;RotateDirection(int value) {this.mValue = value;}public int getValue() {return mValue;}}//构造函数public DraggableFlipView(Context context) {this(context, null);}public DraggableFlipView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public DraggableFlipView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context, attrs);}//初始化参数private void init(Context context, AttributeSet attrs) {//获取布局对象并加以填充,默认显示mBackLayout这个布局mFrontLayout = new RelativeLayout(context);RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);mFrontLayout.setLayoutParams(params1);mBackLayout = new RelativeLayout(context);RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);mBackLayout.setLayoutParams(params2);this.addView(mFrontLayout);this.addView(mBackLayout);mBackLayout.setVisibility(View.INVISIBLE);//初始化FlipListener,传入2个布局,第二个参数为不显示的布局mFlipListener = new FlipListener(mFrontLayout, mBackLayout, this);mDragGestureDetector = new DragGestureDetector(this);//获取 标签TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DraggableFlipView);LayoutInflater.from(context).inflate(a.getResourceId(R.styleable.DraggableFlipView_frontView, DEFAULT_VALUE), mFrontLayout);LayoutInflater.from(context).inflate(a.getResourceId(R.styleable.DraggableFlipView_backView, DEFAULT_VALUE), mBackLayout);//填充标签数据mDraggableAngle = a.getInteger(R.styleable.DraggableFlipView_draggableAngle, DEFAULT_DRAGGABLE_VALUE);mDragDetectAngle = a.getInteger(R.styleable.DraggableFlipView_dragDetectAngle, DEFAULT_DRAG_DETECT_VALUE);}//onInterceptTouchEvent这个事件是从父控件开始往子控件传的,直到有拦截或者到没有这个事件的view,并且使用  mDragGestureDetector.setPointMap(ev);进行参数的传递@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {if (mDragGestureDetector == null) return false;int action = ev.getAction() & MotionEvent.ACTION_MASK;switch (action) {case MotionEvent.ACTION_UP:break;case MotionEvent.ACTION_MOVE:if (Math.abs(ev.getX() - mDragGestureDetector.getTouchPoint().getX())> DRAG_THRESHOLD_PARAM|| Math.abs(ev.getY() - mDragGestureDetector.getTouchPoint().getY())> DRAG_THRESHOLD_PARAM) {mDragGestureDetector.setPointMap(ev);return true;}break;case MotionEvent.ACTION_POINTER_DOWN:return true;}return false;}//onTouch这个事件是从子控件回传到父控件的,一层层向下传//mDragGestureDetector.onTouchEvent(event)来实现onTouchEvent的操作@Overridepublic boolean onTouchEvent(MotionEvent event) {if (mDragGestureDetector != null) {mDragGestureDetector.onTouchEvent(event);}return true;}//计算,并判断以哪种方式来实现切换动画@Overridepublic void onDragGestureListener(DragGestureDetector dragGestureDetector, int action) {if (isAnimation) return;if (action == MotionEvent.ACTION_UP) {if (mAngle >= mDragDetectAngle) {startAutoRotateAnimation(RotateDirection.RIGHT);} else if (mAngle < -mDragDetectAngle) {startAutoRotateAnimation(RotateDirection.LEFT);}return;}mAngle = (dragGestureDetector.deltaX - dragGestureDetector.prevDeltaX) > 0 ? ++mAngle : --mAngle;if (Math.abs(mAngle) > mDragDetectAngle) isDragging = true;if(isDragging) this.setRotationY(mAngle);if (mAngle >= mDraggableAngle) {startAutoRotateAnimation(RotateDirection.RIGHT);} else if (mAngle < -mDraggableAngle) {startAutoRotateAnimation(RotateDirection.LEFT);}}private void startAutoRotateAnimation(RotateDirection rotateDirection) {isAnimation = true;if (mIsReverse) {mFlipListener.reverse();} else {mIsReverse = true;}mFlipListener.setRotateDirection(rotateDirection.getValue());//动画的平滑过渡 可以参照 http://blog.csdn.net/guolin_blog/article/details/43536355//讲的很详细ValueAnimator mFlipAnimator = ValueAnimator.ofFloat(0f, 1f);mFlipAnimator.addUpdateListener(mFlipListener);mFlipAnimator.start();mFlipAnimator.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animation) {}@Overridepublic void onAnimationEnd(Animator animation) {mAngle = 0;isAnimation = false;isDragging = false;}@Overridepublic void onAnimationCancel(Animator animation) {}@Overridepublic void onAnimationRepeat(Animator animation) {}});}
}

DragGestureDetector

public class DragGestureDetector {public float deltaX;public float deltaY;public float prevDeltaX;public float prevDeltaY;public int originalIndex;public float velocityX;public float velocityY;//储存用户操作路径private HashMap<Integer, TouchPoint> pointMap = new HashMap<>();private DragGestureListener dragGestureListener;//构造函数public DragGestureDetector(DragGestureListener dragGestureListener) {this.dragGestureListener = dragGestureListener;//初始化坐标pointMap.put(0, createPoint(0.f, 0.f));}//储存坐标点public void setPointMap(MotionEvent event) {float eventX = event.getX();float eventY = event.getY();TouchPoint downPoint = pointMap.get(0);if (downPoint != null) {downPoint.setXY(eventX, eventY);return;}downPoint = createPoint(eventX, eventY);pointMap.put(0, downPoint);}//获取坐标点public TouchPoint getTouchPoint() {return pointMap.get(originalIndex);}//用户触控坐标点相应的计算synchronized public boolean onTouchEvent(MotionEvent event) {float eventX = event.getX(originalIndex);float eventY = event.getY(originalIndex);int action = event.getAction() & MotionEvent.ACTION_MASK;switch (action) {case MotionEvent.ACTION_DOWN: {break;}case MotionEvent.ACTION_MOVE: {TouchPoint originalPoint = pointMap.get(originalIndex);if (originalPoint != null) {deltaX = eventX - originalPoint.x;deltaY = eventY - originalPoint.y;if (dragGestureListener != null) {dragGestureListener.onDragGestureListener(this, action);}velocityX = deltaX - prevDeltaX;velocityY = deltaY - prevDeltaY;prevDeltaX = deltaX;prevDeltaY = deltaY;}break;}case MotionEvent.ACTION_UP: {TouchPoint originalPoint = pointMap.get(originalIndex);if (originalPoint != null && dragGestureListener != null) {dragGestureListener.onDragGestureListener(this, action);}velocityX = velocityY = 0;prevDeltaX = prevDeltaY = 0;deltaX = deltaY = 0;break;}default:}return false;}private TouchPoint createPoint(float x, float y) {return new TouchPoint(x, y);}public interface DragGestureListener {void onDragGestureListener(DragGestureDetector dragGestureDetector, int action);}//坐标类public class TouchPoint {private float x;private float y;public TouchPoint(float x, float y) {this.x = x;this.y = y;}public TouchPoint setXY(float x, float y) {this.x = x;this.y = y;return this;}public float getX() {return this.x;}public float getY() {return this.y;}}
}

FlipListener

public class FlipListener implements ValueAnimator.AnimatorUpdateListener {private View mParentView;private View mFrontView;private View mBackView;private boolean mFlipped;private int mDirection;//构造函数public FlipListener(final View front, final View back, final View parent) {this.mParentView = parent;this.mFrontView = front;this.mBackView = back;this.mBackView.setVisibility(View.GONE);}@Overridepublic void onAnimationUpdate(final ValueAnimator animation) {final float value = animation.getAnimatedFraction();final float scaleValue = 0.625f + (1.5f * (value - 0.5f) * (value - 0.5f));//根据传入的mDirection(1或者-1)进行计算并且逻辑判断if (value <= 0.5f) {this.mParentView.setRotationY(180 * value * mDirection);if (mFlipped) setStateFlipped(false);} else {this.mParentView.setRotationY(-180 * (1 - value) * mDirection);if (!mFlipped) setStateFlipped(true);}this.mParentView.setScaleX(scaleValue);this.mParentView.setScaleY(scaleValue);}//初始化自定义View时调用public void reverse() {View temp = mBackView;mBackView = mFrontView;mFrontView = temp;}public void setRotateDirection(int direction) {mDirection = direction;}//具体切换试图private void setStateFlipped(boolean flipped) {mFlipped = flipped;this.mFrontView.setVisibility(flipped ? View.GONE : View.VISIBLE);this.mBackView.setVisibility(flipped ? View.VISIBLE : View.GONE);}
}

OK!!!!实现就这些啦
源码:http://yunpan.cn/cHwL97TfNdApF 访问密码 d11f

从头开始敲代码之《从BaseApplication/Activity开始(五)》(自定义控件,实现点击/滑动翻页)...相关推荐

  1. 从头开始敲代码之《从BaseApplication/Activity开始(五)》(自定义控件,实现点击/滑动翻页)

    转载请注明出处:王亟亟的大牛之路 开场白惯用鼓励诗句: 黑发不知勤学早,白首方悔读书迟. -- 颜真卿<劝学诗> 这一系列的博文这是第五篇了,感谢大家的支持以及陪伴,往后我也会继续努力写出 ...

  2. php左右滑动翻页代码,C#_NGUI实现滑动翻页效果实例代码,废话不多说了,直接给大家上 - phpStudy...

    NGUI实现滑动翻页效果实例代码 废话不多说了,直接给大家上干货了. 具体代码如下所示: using UnityEngine; using System.Collections; public cla ...

  3. android控件翻书效果,android ViewPager实现滑动翻页效果实例代码

    实现ViewPager的滑动翻页效果可以使用ViewPager的setPageTransformer方法,如下:import android.content.Context;import androi ...

  4. android 翻书动画效果怎么做,android ViewPager实现滑动翻页效果实例代码

    实现ViewPager的滑动翻页效果可以使用ViewPager的setPageTransformer方法,如下: import android.content.Context; import andr ...

  5. HTML5电子书翻页效果 代码特效+鼠标点击拖拽滑动翻页+点击书页内容放大+不支持中文

    介绍 源码名称:[HTML5电子书翻页效果]代码特效+鼠标点击拖拽滑动翻页+点击书页内容放大+不支持中文 源码大小:237KB 开发语言:PHP+Mysql 操作系统:Windows,Linux 源码 ...

  6. arduino使用oled代码_用Arduino玩转掌控板(ESP32):蓝牙翻页笔(PPT 控制器)

    众所周知,掌控板在创客教育中用的非常广泛,它是一块基于 ESP32 的学习开发板.大家对掌控板编程,用的比较多的都是图形化编程的方式,比如 mPython.Mind+ 等.但是,既然掌控板是基于 ES ...

  7. 从头开始敲代码之《从BaseApplication/Activity开始》

    转载请注明出处王亟亟的大牛之路 其安易持,其未兆易谋:其脆易泮,其微易散.为之于未有,治之于未乱.合抱之木,生于毫末:九层之台,起于垒土:千里之行,始于足下.为者败之,执者失之.是以圣人无为故无败,无 ...

  8. 从头开始敲代码之《从BaseApplication/Activity开始(二)》

    2019独角兽企业重金招聘Python工程师标准>>> 转载请注明出处:王亟亟的大牛之路 愿意花时间写东西不容易,人啊,都是有血有肉有思想的,借鉴是学习,纯Copy就不好了,谢谢 部 ...

  9. Unity中常用的单例模式、对象池的脚本模板,连按退出和滑动翻页或放大缩小的功能实现,以及属性在代码中的灵活使用

    1.单例模式的脚本模板: Unity中针对一些常用的manager可以使用单例模式,用于统一的功能管理: //普通单例,不需要继承MonoBehavior,不用挂载在GameObject上 publi ...

最新文章

  1. C语言嵌入式系统编程修炼
  2. 计算机基础知识关于进制,计算机基础知识-- 进制和编码
  3. api网关揭秘--spring cloud gateway源码解析
  4. IIS 用户验证及授权
  5. mysql报196271错误_微软补丁造成MYSQL及Windows经常连接失败解决方法
  6. Ilya Muromets(DP or 思维)
  7. 【转载】最全最详细Hadoop学习文章
  8. Machine Learning Lecture Notes
  9. word中图片为嵌入式格式时显示不全_毕设时,在word中插入图片时,图片的格式改为嵌入式后图片藏于文字下方怎么办?...
  10. http请求 405错误
  11. 拳皇FANS们不得不看的动画
  12. 使用u盘如何装linux系统教程视频教程,如何使用u盘安装linux系统
  13. 通过ping命令获取各大网站的IP地址
  14. 【安全牛】一起来打靶第二周
  15. mt6799芯片资料mt6799参考设计资料
  16. burnintest激活_PassMark BurnInTest Pro v9.0.1006(拷机软件)真正注册版
  17. Linux驱动编程 step-by-step (二)
  18. 德尔塔病毒劲敌!杨晓明团队发现单抗有效,临床申报正在推进,研究已登Nature子刊...
  19. checkbox jq 监听_「checkbox 选中事件」jquery checkbox 选中、改变状态、change 和 click 事件 - seo实验室...
  20. RE模块:Python编译正则的模块

热门文章

  1. flask中的信号机制
  2. 当session失效后,无论点击那个页面,都找到顶端页面,跳到登录页面。
  3. 18个堪称神器的命令行工具,高效运维必备
  4. 怎么写脚本_直播脚本怎么写|请收下这份攻略
  5. php如何修改xml中element值,php修改xml节点的值
  6. java 模型 视图,部分视图模型
  7. 幻读(phantom read)
  8. 通道Channel-使用NIO 写入数据
  9. initializeBean()方法为容器产生的Bean 实例对象添加BeanPostProcessor 后置处理器
  10. SpringMVC的数据响应-页面跳转-返回ModelAndView形式1(应用)