跳至主要内容

iPhone 向右拖动返回

在 Readibility 第一次体验过这个控件,发现看文章的时候体验非常爽,看完一篇滑一下就可以返回到文章列表。后来网易新闻和新浪微博的 iPhone 客户端也引入了这个控件,于是我就想试试在 微淘 中加入这个手势试试。


图片来源

虽说加入这个控件是我的一时冲动,但分析一下我觉得还是有这个道理的。

  • 很多人都是单手拿着 iPhone 来玩的,这是我在坐车和吃饭的时候看到很多人都这样玩而得到的经验。因此这就有左右手的区别了,然而一般的 app 都是非对称的,比如导航栏左边是个返回按钮,右边是个功能按钮。如果一个人用右手玩 app 的时候,很多时候都很难点击左上的按钮,特别是手指不够修成的女孩。
  • iPhone 5 拿让人蛋痛的4寸屏。以前拿着来刷微博的时候就觉得按导航栏的按钮特别累(我手指已经比较修长了)。但是要我的拇指伸长到4寸来点击那个返回按钮,真是想把它甩了。
  • 这个控件就是很 cool 。

在实现上我纠结了很久,因为学习 obj-c 并不是很长时间,所以有很多特性很不会用,对于现有 app 的代码,我需要动最少的地方来把这个控件接入进来。于是我选了几个入口。

  • 继承 UINavigationController 的 pushViewController 方法做拓展
  • 直接在 UIView 做这个事情

我需要用到的东西包括:

  • 当前的 UIView
  • 上一个页面的 UIView
  • UINavigationController

经过一段时间的考虑,我还是用第二个接入口,而我需要的东西不是前后两个UIView,而且前后两个UIViewController的截屏,然后向 UIView 加入了 UIPanGestureRecognizer 来做手指拖动跟踪。

声明一下,我的代码都是ARC模式的,自己加retain, release, autoRelease就好了

截屏代码:

@implementation UIViewController (ScreenShot)

-(UIImage*)generateScreenShot
{
    CGSize size = [UIScreen mainScreen].bounds.size;
    UIGraphicsBeginImageContextWithOptions(size,YES, 0.0);
    [self.view.window.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

@end

有了这些东西,算法就很简单了,只要对 UIGestureRecognizerStateBegan, UIGestureRecognizerStateChanged, UIGestureRecognizerStateEnded 这几个手势状态来移动两个截图的相对位置就可以了,什么阴影,缩放的都可以随便加入。最后然UIViewController实现一个Delegate,用来检测时候应该弹出做popViewContrller的操作就可以了。

操作代码(不全):

-(void)backGestureRecognized:(UIPanGestureRecognizer*)recognizer
{
    if(_preView==nil) return;
    if(recognizer.state == UIGestureRecognizerStateBegan)
    {
        [self endEditing:YES];
        [self setLayout];
    }
    if (recognizer.state == UIGestureRecognizerStateBegan
        || recognizer.state == UIGestureRecognizerStateChanged) {
        CGPoint point = [recognizer translationInView:self];
        if(point.x>0){
            [self setViewPosition:point];
        }
    } else if (recognizer.state == UIGestureRecognizerStateEnded) {
        if(_currView.frame.origin.x > kBackGestureCommitLength){
            //触发
            [self moveOutSelfWithAnimation:YES];
        }else{
            //未触发
            [self resetStateWithAnimation:YES];
        }
    }
}

源码地址

效果:

拓展一下:

当然越狱用户可以直接使用SwipeBack这个插件来完成这个功能,没有越狱的用户就只能等应用本身支持这个手势的时候才能爽一把了。 ╮(╯▽╰)╭

评论

此博客中的热门博文

Spark 矩阵相乘实现

矩阵相乘计算的意义十分重要,比如我们做数据分析经常使用到的join操作就可以理解成为矩阵相乘的一个部分,矩阵相乘在很多分布式计算框架都有自己的实现,这些实现也可以根据不同大小的矩阵做不同的优化,比如在MapReduce上就有两种基本的实现: 大矩阵乘小矩阵 我可以把小矩阵放到DistrubutedCache,让每个mapper读取,这就是hive的MapJoin的实现。 两个大矩阵相乘 相乘中两个矩阵都是超大矩阵的话,为了减少MapReduce过程中产生的巨大数据,使用的带宽。都会采用矩阵分块的做法,以下会详细介绍这种实现方法。 Spark介绍 官网介绍 超大矩阵拆分计算方法 单机(单线程)矩阵相乘 假设有矩阵 A , B ,相乘的结果为 C ,那么相乘的伪代码: C = 0 for(i <- 0 to A.lenght) for(k <- 0 to A[i].lenght) if(A[i][k]!=0) for(j <- B[k].lenght) { C[i][j] += A[i][k] * B[k][j] } 单机的计算中,时间复杂度是 O(n^3),如果 n 增长到一定程度的时候,那么计算用时就会非常大,所以下面会说一下并行计算方法。 并行矩阵相乘 在计算的过程中,我们很容易发现每个 A[i][k] * B[k][j] 都可以单独计算,因此我也可以单独计算这些组合,最后做一个累计就可以获得 C 矩阵了,相乘伪代码如下: A = ((row, column), value) => (column, (row, value)) B = ((row, column), value) => (row, (column, value)) Temp = A.join(B) => (k, (rowA, valueA), (columnB, valueB)) => ((rowA, columnB), valueA * valueB) => ((rowC, columnC), valueC) C = Temp.reduceByKey =...

iphone 自动打包脚本

最近做ios开发,经常需要给老大打ipa包,这个虽然在xcode中编译并打包是很简单的事,不过每次都得花几分钟的时间做一些手动的放入Payload并压缩成zip包的操作。比较麻烦的是,在开发过程中,突然就说要一个可以执行的包做测试。那么,思路断了,正在写的代码要注释掉,这样持续下去浪费的时间会很多,所以还是需要写一个打包脚本。 打包具体用到的命令是这些: xcodebuild: 主要用于编译项目 xcrun: 主要用于打ipa包 具体打包流程就是编译,然后打一个发布包,一个ipa包,其实用脚本来说话就好了。另外,我用一个conf.dat来存放target和configuration,这些都在xcode里面指定好了,用xxx:xxx这样的格式来存放,xcodebuild在编译的时候会自动找到对应的配置。 打包脚本如下: #!/bin/sh basePath=`pwd` distDir="target" distDir="${basePath}/${distDir}" rm -rdf "$distDir" mkdir -p "$distDir" baseName="xxx" #.app 的名字 projectDir=$(cd ../mobile/xxx; pwd) # 进入xcode工程目录 cd $projectDir for line in $(cat ${basePath}/conf.dat) do targetName=`echo $line | cut -f1 -d':'` conf=`echo $line | cut -f2 -d':'` releaseDir="${projectDir}/build/${conf}-iphoneos" rm -rdf "$releaseDir" echo "======build ${baseName}.app start..." echo "======clean ${conf}..." xcodebuild clean -configuration "$...

【转】ELO-对弈与排名(有触感的排名)

原文: https://www.cnblogs.com/leoin2012/p/4854442.html ELO介绍 ELO等级分制度 是指由 匈牙利 裔 美国 物理学家 Elo创建的一个衡量各类对弈活动水平的评价方法,是当今对弈水平评估的公认的权威方法。被广泛用于 国际象棋 、 围棋 、 足球 、 篮球 等运动。网络游戏 英雄联盟 、 魔兽世界 内的竞技对战系统也采用此分级制度。 历史 ELO等级分制度是基于 统计学 的一个评估棋手水平的方法。 美国 国际象棋 协会在1960年首先使用这种计分方法。由于它比先前的方法更公平客观,这种方法很快流行开来。1970年国际棋联正式开始使用等级分制度。 Elo模型原先采用 正态分布 。但是实践显明棋手的表现并非呈正态分布,所以现在的等级分计分系统通常使用的是 Logistic distribution 。 计分方法 假设棋手A和B的当前等级分分别为 和 ,则按Logistic distribution A对B的胜率期望值当为 类似B对A的胜率为 假如一位棋手在比赛中的真实得分 (胜=1分,和=0.5分,负=0分)和他的胜率期望值 不同,则他的等级分要作相应的调整。具体的数学公式为 公式中 和 分别为棋手调整前后的等级分。在大师级比赛中 通常为16。 例如,棋手A等级分为1613,与等级分为1573的棋手B战平。若K取32,则A的胜率期望值为 ,约为0.5573,因而A的新等级分为1613 + 32 · (0.5 − 0.5573) = 1611.166 国际象棋中的等级分 国际象棋中,等级分和棋联称号的大致对应为 2500分以上:国际特级大师 2400-2499分:国际大师 2300-2399分:棋联大师