19 9月

IOS 转场动画

转场动画

我们需要自定义一个遵循的协议的动画过渡管理对象,并实现两个必须实现的方法.


//返回动画事件 - (NSTimeInterval)transitionDuration:(nullable id)transitionContext; //所有的过渡动画事务都在这个方法里面完成 - (void)animateTransition:(id)transitionContext; 我们还需要自定义一个继承于UIPercentDrivenInteractiveTransition的手势过渡管理对象,我把它成为百分比手势过渡管理对象,因为动画的过程是通过百分比控制.

成为相应的代理,实现相应的代理方法,返回我们前两步自定义的对象就OK了.

转场动画实现的原理

我们以present为例子,如果有其他的也可以用相同的方法实现.

首先,通过viewControllerForKey去出转场前后的两个控制器:


UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; snapshotViewAfterScreenUpdates可以对某个视图截图,我们采用对这个截图做动画代替直接对fromVC做动画,因为在手势过渡中直接使用fromVC动画会和手势有冲突, 如果不需要实现手势的话,就可以不使用截图视图了,大家可以自行尝试一下. UIView *tempView = [fromVC.view snapshotViewAfterScreenUpdates:NO]; tempView.frame = fromVC.view.frame; 因为我们需要对截图做动画,那么fromVC.view就可以隐藏了. fromVC.view.hidden = YES; 这里有个重要的概念containerView,如果要对视图做转场动画,视图就必须要加入containerView中才能进行,可以理解containerView管理着所有做转场动画的视图. 将截图视图和toVC.view都加入到contianerView. [containerView addSubview:tempView]; [containerView addSubview:toVC.view];

设置toVC的frame,因为这里toVC present出来不是全屏,且初始的时候在底部,如果不设置frame的话默认就是整个屏幕咯,这里containerView的frame就是整个屏幕.

现在,我们可以去设置转场动画啦



//通过viewControllerForKey取出转场前后的两个控制器 UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; //snapshotViewAfterScreenUpdates可以对某个视图截图,我们采用对这个截图做动画代替直接对toVC做动画,因为在手势过渡中直接使用toVC动画会和手势有冲突, 如果不需要实现手势的话,就可以不是用截图视图了,大家可以自行尝试一下 UIView *tempView = [fromVC.view snapshotViewAfterScreenUpdates:NO]; tempView.frame = fromVC.view.frame; //因为对截图做动画,vc1就可以隐藏了 fromVC.view.hidden = YES; //这里有个重要的概念containerView,如果要对视图做转场动画,视图就必须要加入containerView中才能进行,可以理解containerView管理着所有做转场动画的视图 UIView *containerView = [transitionContext containerView]; //将截图视图和vc2的view都加入ContainerView中 [containerView addSubview:tempView]; [containerView addSubview:toVC.view]; //设置vc2的frame,因为这里vc2present出来不是全屏,且初始的时候在底部,如果不设置frame的话默认就是整个屏幕咯,这里containerView的frame就是整个屏幕 toVC.view.frame = CGRectMake(0, containerView.height, containerView.width, 400); //开始动画吧,使用产生弹簧效果的动画API [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0 usingSpringWithDamping:0.55 initialSpringVelocity:1.0 / 0.55 options:0 animations:^{ //首先我们让vc2向上移动 toVC.view.transform = CGAffineTransformMakeTranslation(0, -400); //然后让截图视图缩小一点即可 tempView.transform = CGAffineTransformMakeScale(0.85, 0.85); } completion:^(BOOL finished) { //使用如下代码标记整个转场过程是否正常完成[transitionContext transitionWasCancelled]代表手势是否取消了,如果取消了就传NO表示转场失败,反之亦然,如果不用手势present的话直接传YES也是可以的,但是无论如何我们都必须标记转场的状态,系统才知道处理转场后的操作,否者认为你一直还在转场中,会出现无法交互的情况,切记! [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; //转场失败后的处理 if ([transitionContext transitionWasCancelled]) { //失败后,我们要把vc1显示出来 fromVC.view.hidden = NO; //然后移除截图视图,因为下次触发present会重新截图 [tempView removeFromSuperview]; } }]; }

使用如下代码标记整个转场过程是否正常完成[transitionContext transitionWasCancelled]代表手势是否取消了,如果取消了就传NO表示转场失败,反之亦然,如果不用手势present的话直接传YES也是可以的,但是无论如何我们都必须标记转场的状态,系统才知道处理转场后的操作,否则认为你一直还在转场中,会出现无法交互的情况,切记!


[transitionContext completeTransition:![transitionContext transitionWasCancelled]]; //转场失败后的处理 if ([transitionContext transitionWasCancelled]) { //失败后,我们要把vc1显示出来 fromVC.view.hidden = NO; //然后移除截图视图,因为下次触发present会重新截图 [tempView removeFromSuperview]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.navigationController.interactivePopGestureRecognizer.enabled = NO; } } -(void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; // 开启返回手势 if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.navigationController.interactivePopGestureRecognizer.enabled = YES; } }

补充说明:
如果说,我们想使用push去用到自定义present转场动画类,我们可以在VC1->VC2的VC1中去实现UINavigationControllerDelegate协议中的一个方法navigationController: animationControllerForOperation: fromViewController: toViewController:


- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(nonnull UIViewController *)fromVC toViewController:(nonnull UIViewController *)toVC{ if (operation == UINavigationControllerOperationPush){ // 就是在这里判断是哪种动画类型 //这里的PresentTransition就是自定义present方法的动画, //但是我想在push里面用到这个方法 return [[PresentTransition alloc] init]; // 返回push动画的类 }else if(operation == UINavigationControllerOperationPop){ return nil; }else { return nil; } }

本文地址:http://www.laileshuo.com/?p=1251

博客地址:www.laileshuo.com www.laileshuo.cn

05 9月

iOS开发-关闭/收起键盘方法总结

前言:作为IOS开发人员,需要经常和表单打交道。因此我对收起键盘的方法作了下总结,IOS收起键盘有三种方法(如果有其它收起键盘的方法请在留言区指错)。

收起键盘的方法:

1、点击Return按扭时收起键盘

  • (BOOL)textFieldShouldReturn:(UITextField *)textField
    {
    return [textField resignFirstResponder];
    }
    2、点击背景View收起键盘(你的View必须是继承于UIControl)

[self.view endEditing:YES];
3、你可以在任何地方加上这句话,可以用来统一收起键盘

[[[UIApplication sharedApplication] keyWindow] endEditing:YES];
这个方法是我不久前碰到的,觉得有用,就记下来了。

还有一个方法是直接发送 resignFirstResponder 消息:
[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];
该点源自:《iOS开发进阶》 —— 唐巧

总结

我总结出来了四种收起键盘的方法,使用场合如下:当你能获取到 UITextField 对象时,最好使用 [obj resignFirstResponder] 方法; 如果有很多个 UITextField 对象,你也可以获取到 viewController 的 view 时,你可以使用 [[[UIApplication sharedApplication] keyWindow] endEditing:YES] 方法; 如果当前 ViewController比较难获取,那么可以使用第3种或第4种方法。

博文作者:GarveyCalvin

博文出处:http://www.cnblogs.com/GarveyCalvin/

本文版权归作者和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作!

本文地址:http://www.laileshuo.com/?p=1247

博客地址:www.laileshuo.com www.laileshuo.cn

08 8月

iOS应用内跳转到appstore 某个app详情页(广告常见)

iOS应用内跳转到appstore 某个app详情页(广告常见)

应用内直接跳转到appstore,需要添加StoreKit,framework系统库,需要实现下面的代理方法



- (void)skipBtnClick {
    
    SKStoreProductViewController *storeProductViewContorller = [[SKStoreProductViewController alloc] init];
    //设置代理请求为当前控制器本身
    storeProductViewContorller.delegate = self;
    //加载一个新的视图展示
    [storeProductViewContorller loadProductWithParameters:
     //appId唯一的
     @{SKStoreProductParameterITunesItemIdentifier : @"577710538"} completionBlock:^(BOOL result, NSError *error) {
         //block回调
         if(error){
             NSLog(@"error %@ with userInfo %@",error,[error userInfo]);
         }else{
             //模态弹出appstore
             [self presentViewController:storeProductViewContorller animated:YES completion:^{
                 
             }];
         }
     }];
}

代理delegate


//取消按钮监听
- (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController{
    [self dismissViewControllerAnimated:YES completion:^{

    }];
}

如果有不对的地方,还请您留言。转载请注明一下链接。

本文地址:http://www.laileshuo.com/?p=1243

博客地址:www.laileshuo.com www.laileshuo.cn

12 7月

IOS代码片段 类似微博发帖按钮弹簧效果

facebook POP动画引擎,实现类似微博发帖按钮弹簧效果

alt text

代码如下



- (void)show {
    
    for (UIView *subView in self.contentView.subviews) {
        if ([subView isKindOfClass:[MenuButton class]]) {
            CGRect fromRect = subView.frame;
            fromRect.origin.y = CGRectGetMaxY(self.bounds);
            subView.frame = fromRect;
        }
    }
    
    [super showAnimiation:^(BOOL finished) {
        
        NSInteger index = 0;
        for (UIView *subView in self.contentView.subviews) {
            if ([subView isKindOfClass:[MenuButton class]]) {
                MenuButton *menuButton = (MenuButton *)subView;
                double delayInSeconds = index * MenuButtonAnimationInterval;
                CGRect fromRect = menuButton.frame;
                CGRect toRect = menuButton.originFrame;

                [self initailzerAnimationWithToPostion:toRect formPostion:fromRect atView:subView beginTime:delayInSeconds];
                index++;
            }
        }
    }];
}

#pragma mark - Animation

- (void)initailzerAnimationWithToPostion:(CGRect)toRect formPostion:(CGRect)fromRect atView:(UIView *)view beginTime:(CFTimeInterval)beginTime {
    POPSpringAnimation *springAnimation = [POPSpringAnimation animation];
    springAnimation.property = [POPAnimatableProperty propertyWithName:kPOPViewFrame];
    springAnimation.removedOnCompletion = YES;
    springAnimation.beginTime = beginTime + CACurrentMediaTime();
    CGFloat springBounciness = 10 - beginTime * 2;
    //springAnimation.springBounciness = springBounciness;    // value between 0-20
    springAnimation.springBounciness = 5;    // value between 0-20
    
    CGFloat springSpeed = 12 - beginTime * 2;
    springAnimation.springSpeed = springSpeed;     // value between 0-20
    springAnimation.toValue = [NSValue valueWithCGRect:toRect];
    springAnimation.fromValue = [NSValue valueWithCGRect:fromRect];
    
    [view pop_addAnimation:springAnimation forKey:@"POPSpringAnimationKey"];
}

本文作为初学者的学习的记录,以便之后查阅。谢谢。

谢谢您的阅读,希望本站及文档能带给你帮助,给你带来简洁明了的阅读体验。谢谢。

本文地址:http://www.laileshuo.com/?p=669

博客地址:www.laileshuo.com www.laileshuo.cn

12 7月

IOS代码 自带点击抖动动画BUTTON

IOS代码 自带点击抖动动画BUTTON

alt text

代码如下


#import "FlatButton.h" #import @interface FlatButton() - (void)setup; - (void)scaleToSmall; - (void)scaleAnimation; - (void)scaleToDefault; @end @implementation FlatButton + (instancetype)button { return [self buttonWithType:UIButtonTypeCustom]; } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setup]; } return self; } #pragma mark - Private instance methods - (void)setup { [self addTarget:self action:@selector(scaleToSmall) forControlEvents:UIControlEventTouchDown | UIControlEventTouchDragEnter]; [self addTarget:self action:@selector(scaleAnimation) forControlEvents:UIControlEventTouchUpInside]; [self addTarget:self action:@selector(scaleToDefault) forControlEvents:UIControlEventTouchDragExit]; } - (void)scaleToSmall { CASpringAnimation *scaleAnimation = [CASpringAnimation animationWithKeyPath:@"transform.scale.xy"]; scaleAnimation.toValue = @0.95; scaleAnimation.duration = scaleAnimation.settlingDuration; //质量,影响图层运动时的弹簧惯性,质量越大,弹簧拉伸和压缩的幅度越大 Defaults to one scaleAnimation.mass = 5; //刚度系数(劲度系数/弹性系数),刚度系数越大,形变产生的力就越大,运动越快 Defaults to 100 scaleAnimation.stiffness = 100; //阻尼系数,阻止弹簧伸缩的系数,阻尼系数越大,停止越快 Defaults to 10 scaleAnimation.damping = 10; //初始速率,动画视图的初始速度大小 Defaults to zero //速率为正数时,速度方向与运动方向一致,速率为负数时,速度方向与运动方向相反 scaleAnimation.initialVelocity = 10; //估算时间 返回弹簧动画到停止时的估算时间,根据当前的动画参数估算 NSLog(@"====%f",scaleAnimation.settlingDuration); scaleAnimation.duration = scaleAnimation.settlingDuration; //removedOnCompletion 默认为YES 为YES时,动画结束后,恢复到原来状态 //scaleAnimation.removedOnCompletion = NO; // springAnimation.fillMode = kCAFillModeBoth; [self.layer addAnimation:scaleAnimation forKey:@"layerScaleSmallAnimation"]; } - (void)scaleAnimation { CASpringAnimation *scaleAnimation = [CASpringAnimation animationWithKeyPath:@"transform.scale.xy"]; scaleAnimation.toValue = @1.0; scaleAnimation.duration = scaleAnimation.settlingDuration; //质量,影响图层运动时的弹簧惯性,质量越大,弹簧拉伸和压缩的幅度越大 Defaults to one scaleAnimation.mass = 5; //刚度系数(劲度系数/弹性系数),刚度系数越大,形变产生的力就越大,运动越快 Defaults to 100 scaleAnimation.stiffness = 100; //阻尼系数,阻止弹簧伸缩的系数,阻尼系数越大,停止越快 Defaults to 10 scaleAnimation.damping = 10; //初始速率,动画视图的初始速度大小 Defaults to zero //速率为正数时,速度方向与运动方向一致,速率为负数时,速度方向与运动方向相反 scaleAnimation.initialVelocity = 10; //估算时间 返回弹簧动画到停止时的估算时间,根据当前的动画参数估算 NSLog(@"====%f",scaleAnimation.settlingDuration); scaleAnimation.duration = scaleAnimation.settlingDuration; //removedOnCompletion 默认为YES 为YES时,动画结束后,恢复到原来状态 //scaleAnimation.removedOnCompletion = NO; // springAnimation.fillMode = kCAFillModeBoth; [self.layer addAnimation:scaleAnimation forKey:@"layerScaleSpringAnimation"]; } - (void)scaleToDefault { CASpringAnimation *scaleAnimation = [CASpringAnimation animationWithKeyPath:@"transform.scale.xy"]; scaleAnimation.toValue = @1.0; scaleAnimation.duration = scaleAnimation.settlingDuration; //质量,影响图层运动时的弹簧惯性,质量越大,弹簧拉伸和压缩的幅度越大 Defaults to one scaleAnimation.mass = 5; //刚度系数(劲度系数/弹性系数),刚度系数越大,形变产生的力就越大,运动越快 Defaults to 100 scaleAnimation.stiffness = 100; //阻尼系数,阻止弹簧伸缩的系数,阻尼系数越大,停止越快 Defaults to 10 scaleAnimation.damping = 10; //初始速率,动画视图的初始速度大小 Defaults to zero //速率为正数时,速度方向与运动方向一致,速率为负数时,速度方向与运动方向相反 scaleAnimation.initialVelocity = 10; //估算时间 返回弹簧动画到停止时的估算时间,根据当前的动画参数估算 NSLog(@"====%f",scaleAnimation.settlingDuration); scaleAnimation.duration = scaleAnimation.settlingDuration; //removedOnCompletion 默认为YES 为YES时,动画结束后,恢复到原来状态 //scaleAnimation.removedOnCompletion = NO; // springAnimation.fillMode = kCAFillModeBoth; [self.layer addAnimation:scaleAnimation forKey:@"layerScaleDefaultAnimation"]; } @end

本文作为初学者的学习的记录,以便之后查阅。谢谢。

谢谢您的阅读,希望本站及文档能带给你帮助,给你带来简洁明了的阅读体验。谢谢。

本文地址:http://www.laileshuo.com/?p=1231

博客地址:www.laileshuo.com www.laileshuo.cn

11 7月

IOS代码片段 系统的时钟APP里秒表计时效果

facebook POP动画引擎,实现IOS代码片段 系统的时钟APP里秒表计时效果

alt text

代码如下


POPAnimatableProperty *prop = [POPAnimatableProperty propertyWithName:@"countdown" initializer:^(POPMutableAnimatableProperty *prop) { prop.writeBlock = ^(id obj, const CGFloat values[]) { UILabel *lable = (UILabel*)obj; label.text = [NSString stringWithFormat:@"d:d:d",(int)values[0]/60,(int)values[0]%60,(int)(values[0]*100)0]; }; // prop.threshold = 0.01f; }]; POPBasicAnimation *anBasic = [POPBasicAnimation linearAnimation]; //秒表当然必须是线性的时间函数 anBasic.property = prop; //自定义属性 anBasic.fromValue = @(0); //从0开始 anBasic.toValue = @(3*60); //180秒 anBasic.duration = 3*60; //持续3分钟 anBasic.beginTime = CACurrentMediaTime() + 1.0f; //延迟1秒开始 [label pop_addAnimation:anBasic forKey:@"countdown"];

本文作为初学者的学习的记录,以便之后查阅。谢谢。

谢谢您的阅读,希望本站及文档能带给你帮助,给你带来简洁明了的阅读体验。谢谢。

本文地址:http://www.laileshuo.com/?p=669

博客地址:www.laileshuo.com www.laileshuo.cn

11 7月

IOS代码片段 很多金融类app 数字 增加效果

很多金融类app 数字 增加效果
使用facebook POP实现

alt text


// 初始化 POPBasicAnimation *anim = [POPBasicAnimation animation]; // 限时 1s. 2s. anim.duration = 3.0; POPAnimatableProperty * prop = [POPAnimatableProperty propertyWithName:@"count++" initializer:^(POPMutableAnimatableProperty *prop) { prop.readBlock = ^(id obj, CGFloat values[]){ values[0] = [[obj description] floatValue]; }; prop.writeBlock = ^(id obj, const CGFloat values[]) { [obj setText:[NSString stringWithFormat:@"%.2f",values[0]]]; }; prop.threshold = 0.01; }]; anim.property = prop; anim.fromValue = @(0.0); anim.toValue = @(1314.52); [self.g_countLabel pop_addAnimation:anim forKey:@"counting"];

本文作为初学者的学习的记录,以便之后查阅。谢谢。

谢谢您的阅读,希望本站及文档能带给你帮助,给你带来简洁明了的阅读体验。谢谢。

本文地址:http://www.laileshuo.com/?p=1224

博客地址:www.laileshuo.com www.laileshuo.cn

11 7月

Redis的基本使用(基于maven和spring)

使用redis基本测试

maven导包

  <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>2.9.0</version>
  </dependency>

基本连接

public static void main(String[] args) {
// 连接本地的 Redis 服务
Jedis jedis = new Jedis(“localhost”);
System.out.println(“连接成功”);
// 查看服务是否运行
System.out.println(“服务正在运行: ” + jedis.ping());
}

存入string类型的值

public static void main(String[] args) {
// 连接本地的 Redis 服务
Jedis jedis = new Jedis(“localhost”);
//使用字符串string存值
jedis.set(“城市”, “南京”);
}

在图形化redis客户端可以看到,存值成功

alt text

string类型取值

Jedis jedis = new Jedis(“localhost”);
String city = jedis.get(“城市”);

存入list集合类型的值

public static void main(String[] args) {
// 连接本地的 Redis 服务
Jedis jedis = new Jedis(“localhost”);
//使用字符串list存值
jedis.lpush(“城市”, “南京”);
jedis.lpush(“城市”, “上海”);
jedis.lpush(“城市”, “苏州”);
jedis.lpush(“城市”, “北京”);
jedis.lpush(“城市”, “南通”);
}

图形化界面展示效果

alt text

list集合取值

public static void main(String[] args) {
// 连接本地的 Redis 服务
Jedis jedis = new Jedis(“localhost”);
//list集合取值,这里注意的是,100的位置是结束的角标,如果大了没事,小了的话就会缺
List arr = jedis.lrange(“城市”, 0, 100);
System.out.println(arr.size());
for (String string : arr) {
System.out.println(string);
}
}

存入Map的值
map类型存值又叫Redis hash ,是一个string类型的field和value的映射表

public static void main(String[] args) {
//连接本地的jedis服务器
Jedis jedis=new Jedis(“localhost”);

    //Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
    //这里要求的是map必须是key和value都是string类型的
    Map<String, String> map=new HashMap<>();
    map.put("name", "小明");
    map.put("age", "13");
    map.put("sex", "男");
    map.put("height", "174");

    //调用jedis的hmset(存入hash map)的方法将map的键值对存进去
    jedis.hmset("people", map);
}

图形化客户端界面显示为:

alt text

map取值

public static void main(String[] args) {
//连接本地的jedis服务器
Jedis jedis=new Jedis(“localhost”);

    //新建一个string类型的数组,用于存当时存入redis的map的key值
    String[] arr=new String[4];
    arr[0]="name";
    arr[1]="age";
    arr[2]="sex";
    arr[3]="height";
    //利用jedis的hmget方法,从数据库中依次取出对应的map的key值
    List<String> list = jedis.hmget("people",arr);
    for (int i = 0; i < arr.length; i++) {
        System.out.println("存入键值对为:"+arr[i]+"--"+list.get(i));
    }

}

结果为:

存入键值对为:name–小明
存入键值对为:age–13
存入键值对为:sex–男
存入键值对为:height–174
存入Set的值
Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

存入代码:

public static void main(String[] args) {
//连接本地的jedis服务器
Jedis jedis=new Jedis(“localhost”);

    //使用list存入数据
    List<String> list=new ArrayList<>();
    list.add("北京");
    list.add("南京");
    list.add("上海");
    list.add("北京");
    list.add("北京");
    list.add("上海");
    list.add("苏州");
    list.add("南京");
    //打印源数据
    System.out.println("源数据为"+list);

    //因为jedis的sadd的方法,存入的是一个数组对象或者多数据,所有将集合对象转换成数组对象
    String[] arr=new String[list.size()];
    for (int i = 0; i < arr.length; i++) {
        arr[i]=list.get(i);
    }
    //调用sadd方法存入数据库
    jedis.sadd("city", arr);

}

原来数据为:

源数据为[北京, 南京, 上海, 北京, 北京, 上海, 苏州, 南京]
redis数据库图形化客户端显示

alt text

可见,存入后,是把数据去重之后存储的.

set数据的取出

public static void main(String[] args) {
//连接本地的jedis服务器
Jedis jedis=new Jedis(“localhost”);

    //调用jedis的smembers方法,获取所有的set集合
    Set<String> smembers = jedis.smembers("city");

    System.out.println(smembers);
}

控制台结果为:

[北京, 上海, 南京, 苏州]
存入sortset的值
Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。

存入代码:

public static void main(String[] args) {
//连接本地的jedis服务器
Jedis jedis=new Jedis(“localhost”);

    Map<String, Double> map=new HashMap<>();
    map.put("北京", 1.0);
    map.put("北京", 2.0);
    map.put("南京", 3.0);
    map.put("上海", 4.0);
    map.put("上海", 5.0);
    map.put("南京", 6.0);

    //调用jedis的zadd方法存入
    jedis.zadd("city", map);
}

图形化客户端界面:

alt text

南京在放入map时候,是在上海之前,可是最后score却取的是后面的一个.可见,如果有重复的数据产生的话,去重是将前面序号的重复去掉

取出代码:

public static void main(String[] args) {
//连接本地的jedis服务器
Jedis jedis=new Jedis(“localhost”);

    //索引在0,到10之间的,分数由高到底的取出所有的集合
    Set<String> zrevrange = jedis.zrevrange("city", 0, 10);
    System.out.println(zrevrange);

}

控制台输出:

[南京, 上海, 北京]

使用redis的基于spring测试
使用spring整合

applicationContext.xml中配置

名称空间:

xmlns:cache=”http://www.springframework.org/schema/cache”
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd”>
配置文件:




<cache:annotation-driven cache-manager="redisCacheManager" />

<!-- jedis 连接池配置 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxIdle" value="300" />
    <property name="maxWaitMillis" value="3000" />
    <property name="testOnBorrow" value="true" />
</bean>

<!-- redis的连接工厂 -->
<bean id="connectionFactory"
    class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
    p:host-name="localhost" p:port="6379" p:pool-config-ref="poolConfig"
    p:database="0" />

<!-- spring data 提供 redis模板  -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
    <property name="connectionFactory" ref="connectionFactory" />
    <property name="keySerializer">
        <bean
            class="org.springframework.data.redis.serializer.StringRedisSerializer" />
    </property>
    <property name="valueSerializer">
        <bean
            class="org.springframework.data.redis.serializer.StringRedisSerializer">
        </bean>
    </property>
</bean>

在需要使用的service类中,使用注解

//自动注入redis模板
@Autowired
private RedisTemplate<String, String> redisTemplate;

使用spring整合string类型的值

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext.xml”)
public class RedisTest {

@Autowired
private RedisTemplate<String, String> redisTemplate;

@Test
public void Test01(){
    //通过模板,获取到String类型的redis对象
    ValueOperations<String, String> redisString = redisTemplate.opsForValue();

    //使用set方法,保存key和value的值
    redisString.set("city", "南京");

    //使用get(key)的方法获取到city对应的值
    String string = redisString.get("city");
    System.out.println(string);
}

}

图形化界面:

alt text

控制台输出:

alt text

使用spring整合list类型的值

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext.xml”)
public class RedisTest {

@Autowired
private RedisTemplate<String, String> redisTemplate;

@Test
public void Test01(){

    //通过模板获取list类型的redis
    ListOperations<String, String> redisList = redisTemplate.opsForList();

    //通过key依次插入数据
    redisList.leftPush("city", "南京");
    redisList.leftPush("city", "上海");
    redisList.leftPush("city", "北京");
    redisList.leftPush("city", "上海");
    redisList.leftPush("city", "南京");

    //查找索引范围内的所有数据
    List<String> range = redisList.range("city", 0, 10);
    System.out.println(range);

}

}

图形化客户端:

alt text

结果:

[南京, 上海, 北京, 上海, 南京]
使用spring整合Hash类型的值

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext.xml”)
public class RedisTest {

@Autowired
private RedisTemplate<String, String> redisTemplate;

@Test
public void Test01(){

    //通过模板对象,获取到redis的hash类型的对象
    HashOperations<String, Object, Object> redisMap = redisTemplate.opsForHash();

    //建立map集合
    Map<String, String> map=new HashMap<>();

    map.put("name", "小明");
    map.put("age", "18");
    map.put("length", "175");

    //存储hash对象
    redisMap.putAll("people", map);

    //获取数据库中存储的集合的key
    Set<Object> keys = redisMap.keys("people");
    //遍历key集合,获取到map中所有的value值
    for (Object key : keys) {
        Object value = redisMap.get("people", key);
        System.out.println(key+":"+value);
    }
}

}

图形化客户端界面:

alt text

取值后的控制台界面:

name:小明
length:175
age:18
使用spring整合Set类型的值
代码示例:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext.xml”)
public class RedisTest {

@Autowired
private RedisTemplate<String, String> redisTemplate;

@Test
public void Test01(){
    //通过redis模板,创建set类型的redis对象
    SetOperations<String, String> redisSet = redisTemplate.opsForSet();

    //新建数组,赋值
    String[] arr=new String[5];
    arr[0]="南京";
    arr[1]="北京";
    arr[2]="南京";
    arr[3]="上海";
    arr[4]="北京";

    //调用set的add方法,存入key和数组
    redisSet.add("city", arr);

    //通过redis的获取成员方法,利用key获取到set集合
    Set<String> members = redisSet.members("city");
    System.out.println(members);

}

}

图形化数据客户端界面:

alt text

控制台界面:

[北京, 南京, 上海]
由此可见,set类型的redis不是固定顺序的.

使用spring整合sortSet类型的值
由于set类型是不具有顺序的,而sortSet类型则具有顺序

代码示例:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext.xml”)
public class RedisTest {

@Autowired
private RedisTemplate<String, String> redisTemplate;

@Test
public void Test01(){

    //使用模板创建ZSet对象
    ZSetOperations<String, String> redisZSet = redisTemplate.opsForZSet();

    //存值,存value的同时,还加上顺序
    redisZSet.add("city", "南京", 1);
    redisZSet.add("city", "北京", 2);
    redisZSet.add("city", "上海", 3);
    redisZSet.add("city", "南京", 4);
    redisZSet.add("city", "上海", 5);
    redisZSet.add("city", "南京", 6);

    //获取范围顺序里面的值
    Set<String> rangeByScore = redisZSet.rangeByScore("city", 1, 10);
    System.out.println(rangeByScore);

}

}

图形化客户端界面:

alt text

控制台数据:

[北京, 上海, 南京]
效果同之前一样.

来源 https://www.cnblogs.com/wangxinblog/p/7349638.html

谢谢您的阅读,希望本站及文档能带给你帮助,给你带来简洁明了的阅读体验。谢谢。

本文地址:http://www.laileshuo.com/?p=1220

博客地址:www.laileshuo.com www.laileshuo.cn

11 7月

IOS代码 保存视频到相册中

//IOS保存视频到相册中
- (void)saveVideoPath:(NSString *)videoPath {
    NSURL *url = [NSURL fileURLWithPath:videoPath];

    //标识保存到系统相册中的标识
    __block NSString *localIdentifier;

    //首先获取相册的集合
    PHFetchResult *collectonResuts = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
    //对获取到集合进行遍历
    [collectonResuts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        PHAssetCollection *assetCollection = obj;
        //folderName是我们写入照片的相册
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            //请求创建一个Asset
            PHAssetChangeRequest *assetRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url];
            //请求编辑相册
            PHAssetCollectionChangeRequest *collectonRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
            //为Asset创建一个占位符,放到相册编辑请求中
            PHObjectPlaceholder *placeHolder = [assetRequest placeholderForCreatedAsset];
            //相册中添加视频
            [collectonRequest addAssets:@[placeHolder]];

            localIdentifier = placeHolder.localIdentifier;
        } completionHandler:^(BOOL success, NSError *error) {
            if (success) {
                NSLog(@&quot;保存视频成功!&quot;);
            } else {
                NSLog(@&quot;保存视频失败:%@&quot;, error);
            }
        }];
        //        }
        *stop = YES;
    }];
}

谢谢您的阅读,希望本站及文档能带给你帮助,给你带来简洁明了的阅读体验。谢谢。

本文地址:http://www.laileshuo.com/?p=1217

博客地址:www.laileshuo.com www.laileshuo.cn

11 7月

MySQL查询优化:连接查询排序limit(join、order by、limit语句)

MySQL查询优化:连接查询排序limit(join、order by、limit语句)

不知道有没有人碰到过这样恶心的问题:两张表连接查询并limit,SQL效率很高,
但是加上order by以后,语句的执行时间变的巨长,效率巨低。

情况是这么一个情况:现在有两张表,team表和people表,每个people属于一个
team,people中有个字段team_id。

下面给出建表语句:

[sql]

create table t_team

(

id int primary key,

tname varchar(100)

);

create table t_people

(

id int primary key,

pname varchar(100),

team_id int,

foreign key (team_id) references t_team(id)

);

下面我要连接两张表查询出前10个people,按tname排序。

于是,一个SQL语句诞生了:select * from t_people p left join t_team t onp.
team_id=t.id order by p.pname limit 10; [语句①]

这个是我第一反应写的SQL,通俗易懂,也是大多数人的第一反应。

然后来测试一下这个语句的执行时间。

首先要准备数据。我用存储过程在t_team表中生成1000条数据,在t_people表中
生成100000条数据。(存储过程在本文最后)

执行上面那条SQL语句,执行了好几次,耗时在3秒左右。

再换两个语句对比一下:

1.把order by子句去掉:select * from t_people p left join t_team t on p.team_id=
t.id limit10; [语句②]

耗时0.00秒,忽略不计。

2.还是使用order by,但是把连接t_team表去掉:select * from t_people p order
by p.pname limit 10; [语句③]

耗时0.15秒左右。

对比发现[语句①]的效率巨低。

为什么效率这么低呢。[语句②]和[语句③]执行都很快,[语句①]不过是二者的结合。
如果先执行[语句③]得到排序好的10条people结果后,再连接查询出各个people的
team,效率不会这么低。那么只有一个解释:MySQL先执行连接查询,再进行排序。

解决方法:如果想提高效率,就要修改SQL语句,让MySQL先排序取前10条再连接查询。

SQL语句:

select * from (select * from t_people p order by p.pname limit 10) p left join t_team
t on p.team_id=t.id limit 10; [语句④]

[语句④]和[语句①]功能一样,虽然有子查询,虽然看起来很别扭,但是效率提高了很多,
它的执行时间只要0.16秒左右,比之前的[语句①]提高了20倍。

这两个表的结构很简单,如果遇到复杂的表结构…我在实际开发中就碰到了这样的
问题,使用[语句①]的方式耗时80多秒,但使用[语句④]只需1秒以内。

最后给出造数据的存储过程:

[sql]

CREATE PROCEDURE createdata()

BEGIN

DECLARE i INT;

START TRANSACTION;

SET i=0;

WHILE i<1000 DO

INSERT INTO t_team VALUES(i+1,CONCAT('team',i+1));  

SET i=i+1;  

END WHILE;

SET i=0;

WHILE i<100000 DO

INSERT INTO t_people VALUES(i+1,CONCAT('people',i+1),i%1000+1);  

SET i=i+1;  

END WHILE;

COMMIT;

END

来源 https://blog.csdn.net/xiao__gui/article/details/8616224

谢谢您的阅读,希望本站及文档能带给你帮助,给你带来简洁明了的阅读体验。谢谢。

本文地址:http://www.laileshuo.com/?p=1214

博客地址:www.laileshuo.com www.laileshuo.cn