基本数据采集

经过体验,手机QQ采用的应该是线性动画,即视图缩放比例等随手指在屏幕上滑动的距离以一次方程的形式变化。

提取基本数据,向右侧滑达到最大幅度时:

1、   右侧主视图左边界距离屏幕左边界的距离占屏幕宽度的比例为:78%

2、   右侧主视图的高度占屏幕高度的比例为:77%

分步实现:

1、实现主视图的缩放侧滑;

2、实现主视图与左视图的联动;

第一步,实现主视图的缩放侧滑

此前动手做时参考了一些类似的demo,发现许多是用手势UIPanGestureRecognizer来实现的,而本文将采用UITouch。并使用以下两个触摸触发事件:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

原理:

主视图mainVC的移动和缩放:

①. 主视图frmae的x坐标 = 主视图frmae的x坐标 + 手指滑动的x轴总偏移量偏移量;

#pragma mark - 手指在屏幕上移动
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{ if ([event touchesForView:_mainVC.view]) { // 获取UITouch对象
UITouch *touch = [touches anyObject]; // 获取当前点
CGPoint currentPoint = [touch locationInView:self.view]; // 获取上一个点
CGPoint prePoint = [touch previousLocationInView:self.view]; // x轴偏移量:当手指移动一点的时候,x偏移多少
CGFloat offsetX = currentPoint.x - prePoint.x; // 设置当前主视图的frame
_mainVC.view.frame = [self getCurrentFrameWithOffsetX:offsetX]; // 移动渐变效果 (明 - 暗)
_blackCover.alpha = (1 - _mainVC.view.frame.origin.x / RTarget); } // 判断是拖拽 还是 点击tap
_isDraging = YES;
}

②. 主视图的缩放比例 :

// 当手指偏移一点,根据X轴的偏移量算出当前主视图的frame
- (CGRect)getCurrentFrameWithOffsetX:(CGFloat)offsetX
{ // 获取y轴偏移量,手指每移动一点,y轴偏移多少
CGFloat offsetY = offsetX * _maxOffestHight / screenWidth; // 每次移动缩小比例
CGFloat scale = (screenHeight - 2 * offsetY) / screenHeight; #if 0
if (offsetX < 0 && _mainVC.view.frame.origin.x <= 0)
{ // 往左边滑动
scale = (screenH + 2 * offsetY) / screenH; }
#endif // 获取之前的frame *************** 限制成只能显示左视图!
CGRect frame = _mainVC.view.frame; if ((frame.origin.x+offsetX) >=0 )
frame.origin.x += offsetX;
else
frame.origin.x = 0; frame.size.height = frame.size.height *scale;
frame.size.width = frame.size.width *scale;
frame.origin.y = (screenHeight - frame.size.height) / 2.0; return frame;
}

/**  当手指偏移一点,根据X轴的偏移量算出当前主视图的frame **/

// 获取y轴偏移量,手指每移动一点,y轴偏移多少

CGFloat offsetY = offsetX * _maxOffestHight / screenWidth;

// 每次移动缩小比例

CGFloat scale = (screenHeight - 2 * offsetY) / screenHeight;

CGRect frame = _mainVC.view.frame;

… …

/** 主视图的位置变化 和 大小缩放 **/

frame.origin.x += offsetX;

frame.size.height = frame.size.height *scale;

frame.size.width = frame.size.width *scale;

frame.origin.y = (screenHeight - frame.size.height) / 2.0;

… …

第二步,实现主视图与左视图的联动

原理:

重点是找出线性关系,然后联动可以这样做 :

1、这是leftVC.view的缩放比例:

找出这两点 (0.77 ,0) (1 ,screenwidth
* 0.78),即(left.view的缩放比例, main.view.x坐标),可得线性关系:

CGFloat leftScale = ((1 - _minSclae)/(screenWidth * _boundScale))*_mainVC.view.frame.origin.x + _minSclae;
leftCX = _mainVC.view.frame.origin.x >= screenWidth * _boundScale ? self.view.center.x : leftCX;

2、这是leftVC.view的移动:

找出这两点(self.view.center.x ,
screenwidth * 0.78) (center - 80 , 0),即(屏幕中心点x的坐标 ,main.view.or.x坐标),可得线性关系:

    CGFloat leftCX = ( _leftCenterFactor / (screenWidth * _boundScale) )*_mainVC.view.frame.origin.x + screenWidth/2 - _leftCenterFactor;

    leftScale = leftScale >= 1 ? 1 :leftScale;

3、最后移动和缩放:

_leftVC.view.center = CGPointMake(leftCX, self.view.center.y);

    _leftVC.view.transform = CGAffineTransformScale(CGAffineTransformIdentity, leftScale, leftScale);

完整代码:

/**
* 开启左视图联动事件
*/
- (void)startedLeftViewLinkage
{
// 执行左视图联动动画 // (self.view.center.x , screenwidth * 0.78) (center - 80 , 0) ==> (中心点x的坐标 ,main.view.or.x坐标),线性关系
CGFloat leftCX = ( _leftCenterFactor / (screenWidth * _boundScale) )*_mainVC.view.frame.origin.x + screenWidth/2 - _leftCenterFactor;
leftCX = _mainVC.view.frame.origin.x >= screenWidth * _boundScale ? self.view.center.x : leftCX; // (0.77 , 0) (1 , screenwidth*0.78) ==》 (left.view的缩放比例, main.view.or.x坐标),线性关系
CGFloat leftScale = ((1 - _minSclae)/(screenWidth * _boundScale))*_mainVC.view.frame.origin.x + _minSclae;
leftScale = leftScale >= 1 ? 1 :leftScale; _leftVC.view.center = CGPointMake(leftCX, self.view.center.y);
_leftVC.view.transform = CGAffineTransformScale(CGAffineTransformIdentity, leftScale, leftScale);
}

最后,松开手指事件:

#pragma mark - 停止移动

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([event touchesForView:_mainVC.view]) { // 点击tap事件 复位满屏
if (_isDraging == NO && _mainVC.view.frame.origin.x != 0) { [UIView animateWithDuration:0.25 animations:^{ _mainVC.view.frame = self.view.bounds;
}];
} CGFloat target = 0; if (_mainVC.view.frame.origin.x > screenWidth / 3) { // 定位到右边
target = RTarget; }else if (CGRectGetMaxX(_mainVC.view.frame) < screenWidth / 3) { // 定位到左边
target = LTarget; } // 停止拖拽时判断是显示左视图还是主视图
[UIView animateWithDuration:0.25 animations:^{ if (target) { // 在需要定位左边或者右边 // 获取x轴偏移量
CGFloat offsetX = target - _mainVC.view.frame.origin.x; // 设置当前主视图的frame
_mainVC.view.frame = [self getCurrentFrameWithOffsetX:offsetX];
_blackCover.alpha = (1 - _mainVC.view.frame.origin.x / RTarget); }else{ // 还原
_mainVC.view.frame = self.view.bounds;
_blackCover.alpha = (1 - _mainVC.view.frame.origin.x / RTarget);
} // 开启左视图联动
[self startedLeftViewLinkage];
}];
} _isDraging = NO;
}

以上是对左视图和主视图的移动及缩放关系的解析,侧滑的关键就是找准视图之间的内在动态联系。按本文方法可达到高仿,实现的效果基本与手机QQ一样。

 

实现“手机qq”侧滑菜单 -- 吴欧的更多相关文章

  1. 再造 “手机QQ” 侧滑菜单(三)——视图联动

    代码示例:https://github.com/johnlui/SwiftSideslipLikeQQ 本 文中,我们将一起使用 UINavigationController 来管理主视图,并实现点击 ...

  2. 再造 “手机QQ” 侧滑菜单(一)——实现侧滑效果

    本系列文章中,我们将尝试再造手机QQ的侧滑菜单,力争最大限度接近手Q的实际效果,并使用 Auto Layout 仿造左侧菜单,实现和主视图的联动. 代码示例:https://github.com/jo ...

  3. 再造 “手机QQ” 侧滑菜单(二)——高仿左视图

    代码示例:https://github.com/johnlui/SwiftSideslipLikeQQ 本篇文章中,我们将一起使用 Auto Layout 高仿手Q的左侧视图,力争达成从布局到动画的全 ...

  4. 自定义控件?试试300行代码实现QQ侧滑菜单

    Android自定义控件并没有什么捷径可走,需要不断得模仿练习才能出师.这其中进行模仿练习的demo的选择是至关重要的,最优选择莫过于官方的控件了,但是官方控件动辄就是几千行代码往往可能容易让人望而却 ...

  5. iOS仿QQ侧滑菜单、登录按钮动画、仿斗鱼直播APP、城市选择器、自动布局等源码

    iOS精选源码 QQ侧滑菜单,右滑菜单,QQ展开菜单,QQ好友分组 登录按钮 3分钟快捷创建高性能轮播图 ScrollView嵌套ScrolloView(UITableView .UICollecti ...

  6. Swift实战-小QQ(第2章):QQ侧滑菜单

    QQ侧滑实现架构:需要建立以下几个ViewController:1.XQBaseViewController 2.LeftViewController3.RightViewController4.Co ...

  7. 仿QQ侧滑菜单<大自然的搬运工-代码不是我的>

    1.记录下效果图 2.二个工具类 package myapplication.com.myapplicationfortest.utils; import android.util.Log; /** ...

  8. 类似QQ侧滑菜单功能实现

    之前的那文章简单实现了菜单侧拉功能,但是做不到像QQ那样导航条和tabBar一起移动...之后在网上找资料,有了思路,就自个写了个demo试试水. 先创建QHLMainController控制器,并把 ...

  9. css3实现手机qq空间菜单按钮

    工作之余写的一个类似于QQzone的菜单效果 先上截图: 图一为点击按钮前界面: 图二为点击按钮后的界面 下面上代码: <!--css部分--> <style type=" ...

随机推荐

  1. 初识python 之 cx_oracle

    使用cx_oracle操作oracle数据库 oracleClient 包 #!/user/bin env python # author:Simple-Sir # create_time: 2021 ...

  2. JDK_win10环境下安装JDK8时点击下一步没反应的解决办法

    问题现象 打开JDK8,点击下一步就没后续了... 解决方法 百度了一下"win10安装jdk8点下一步无响应" . 按照博客中说的操作试了下...安装成功了... 只想说...什 ...

  3. redis 重启服务丢失 密码设置 现象 与 解决过程

    1. 前言 今天开电脑,开启redis服务后,项目使用redis的时候提示 不能找到 redisPools,并提示密码错误, 然后我用cmd打开却可以使用,真是奇了怪了!!! 2.使用现象: (1)c ...

  4. CentOS6.5-Hadoop2.7.3安装hive-2.1.1

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6627723801960382979/ 系统版本,Hadoop已安装完成 Mysql安装完成 准备的解压包 安装zi ...

  5. HDOJ1573X问题

    https://acm.hdu.edu.cn/showproblem.php?pid=1573 n组线性同余方程求解,最后求出多少解.而最终的解的周期为最小公倍数,范围内的,需要这样算.如果最小超过, ...

  6. 机器学习|线性回归三大评价指标实现『MAE, MSE, MAPE』(Python语言描述)

    原文地址 ?传送门 对于回归预测结果,通常会有平均绝对误差.平均绝对百分比误差.均方误差等多个指标进行评价.这里,我们先介绍最常用的3个: 平均绝对误差(MAE) 就是绝对误差的平均值,它的计算公式如 ...

  7. 文件上传之结合phpinfo与本地文件包含利用

    背景 某站点存在本地文件包含及phpinfo,可以利用其执行脚本. 原理 原理: 利用php post上传文件产生临时文件,phpinfo()读临时文件的路径和名字,本地包含漏洞生成1句话后门 1.p ...

  8. PHP代码审计之create_function()函数

    0x00 create_function()简介 适用范围:PHP 4> = 4.0.1,PHP 5,PHP 7 功能:根据传递的参数创建匿名函数,并为其返回唯一名称. 语法: 1 create ...

  9. SpringBoot2.4.2下配置Lettuce使用Redis

    1. Springboot2.4.2下对Redis的基础集成 1.1 maven添加依赖 <dependency> <groupId>org.springframework.b ...

  10. 手写Webserver

    一.反射 反射Reflection:把java类中的各种结构(方法.属性.构造器.类名)映射成一个个的java对象.利用反射技术可以对一个类进行解剖,反射是框架设计的灵魂 //在运行期间,一个类,只有 ...