实现一个简单的按钮实例-上下左右,左旋转,右旋转,放大缩小。代码重构

本文介绍了如何通过Block来优化iOS应用中按钮的上下左右移动、旋转和缩放动画,通过提取公共代码,减少代码冗余,提高代码复用性和可读性。详细讲解了Block的使用方法以及在动画实现过程中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

因为除了上下左右旋转按钮,缩放这些实现方法不一样,他们的实现动画功能都是一样的,所以这里可以把他们实现动画功能提出来,用力block(代码块)。(就类似上下左右移动,左右旋转,伸缩等也是把他们相同的地方包装在一起,在UIView里面把四个按钮拖在到一个方法里面,把左右旋转也拖拽到一个方法里面,把伸缩拖拽到一个方法里面,然后用tag来识别是要操作那个按钮。)  下面来实现block。

不过在使用block前,也可以用方法

把动画开始的两句写在一个方法里面,然后用self调用这个方法

- (void)start{

    //实现动画

    [ UIViewbeginAnimations:nilcontext:nil];


    //设置动画执行时间

    [UIViewsetAnimationDuration:2.0];

}

把介绍写在另外一个方法里面,同样用self调用

- (void)end{

   [UIViewcommitAnimations];

}

然后再之前写这两个方法的地方,替换上面的方法。


二、也可以用函数


void start(){

//实现动画

    [ UIViewbeginAnimations:nilcontext:nil];


    //设置动画执行时间

    [UIViewsetAnimationDuration:2.0];

}

void end(){

 [UIViewcommitAnimations];

}

上面的方法也是比较冗余。


三、用block方法

//

//  ViewController.m

//  ios练习-qq登录

//

//  Created by 陈军 on 16/3/15.

//  Copyright (c) 2016 陈军. All rights reserved.

//


#import "ViewController.h"


#define kdelta 20

@interface ViewController ()


@end


@implementation ViewController


// 比较冗余

//void start(){

    //实现动画

//    [ UIView beginAnimations:nil context:nil];


    //设置动画执行时间

//    [UIView setAnimationDuration:2.0];

    

//}


//void end(){

 //    [UIView commitAnimations];

//}




#pragma mark block来提出动画的

//(id)sender 就是tag,要点击哪个按钮,就传进来

// 要使用这个block把代码块封装起来,就是因为下面的上下左右,旋转,伸缩,他们的动画代码都是一样的,所以用block把代码块抽出来,然后把用self调用这个方法

//- (void)btnClick:(id)sender block:(void(^)())block,本来是要用这个的,但是这里不需要调用tag,所以就不用写了这个了

- (void)btnClickWithBlock:(void(^)())block{


    //(void(^)())block 为什么要这么写得,正常定义block void (^block) ()  最后面的括号为空的话,可以省略但是这里为什么要这样写呢(void(^)())block 分来来写,void(^)())是类型,然后把void(^block)())中的block放在右边,所以就是(void(^)())block这个了



    //实现动画

    [UIView beginAnimations:nil context:nil];


    //设置动画执行时间

    [UIView setAnimationDuration:2.0];


    //这里就是把要使用的代码块调用进来。之所以是在这里调用这个block,是因为,上下左右,左旋转 右旋转  伸缩 的代码是夹在动画的开始和结束之间的

    block();



        [UIView commitAnimations];


}



/*

#pragma mark 向上走的实现方法


- (IBAction)up:(id)sender {

    //添加动画,是为了让效果更好看,用法就是把这个方法上下包住

    //动画是一个UIView的类方法,[UIView beginAnimations:(NSString *) context:(void *)]; 在大部分情况下,(NSString *) (void *)都直接为空

    //动画开始,是慢慢的执行

    [UIView beginAnimations:nil context:nil];


    //设置动画的执行时间,也是一个UIView类方(double类型,所以有小数点)

    [UIView setAnimationDuration:2.0]; // 时间是以秒为单位。这个类方法的意思就是y值,点击向上一次的时间是2秒,这个可以随便修改

    


    //两种获得button这个属性的方法,为什么要获得button能,因为最后是要控制这个button,所以要获得它

    //_button;// 这个是获得button第一种方法


    //因为要控制button向上走,所以是控制y(y值是向上向下,x值是向左向右),而这个xy值都是在frame属性中,frameUIButton中得属性,而UIButton是继承UIView

    //self.button;// 这个是获得button第二种方法


    //这个是修改y值,因为frame中得origin是控制坐标的(x,y)size是控制宽高的(height,width) 向上是减等于,向下是加等于,所以要修改y的值就用下面这个方法

    //self.button.frame.origin.y -= 5; // 这样写法虽然看似没有错,但是oc语法有规定,不能直接修改某个对象中结构体的属性成员,所以也不能这样写self.button.frame.origin.y -=10;

    //1.先取出frame,但是frame属于CGRect,所以定义一个CGRect的变量frame,把self.button.frame; 赋值给变量frame

    CGRect frame = self.button.frame; //这个语句是先把self.button.frame拿出来赋值给一个新的frame,这个frameself.button.frame;中得frame没有关系

    //2.修改y

    //frame.origin.y = frame.origin.y - 20;//这个语句有一种简单的方法,

    //if(tag == 1){

    frame.origin.y -= 20;

    //}


    //3.重新赋值按钮的frame,虽然frame.origin.y -= 5;这个是每点击一次y值减少5,但是只是减少的CGRect frame,和self.button.frame;没有关系,所以必须得把CGRect frame重新赋值回去

    self.button.frame = frame; // 这样就能够实现点击向上按钮一次就向上走一次。

    //动画结束,也是UIView类方法,提交动画或者执行动画

    [UIView commitAnimations];


}


#pragma mark 向下走的实现方法

- (IBAction)lower:(id)sender {


    //实现动画效果

    [ UIView beginAnimations:nil context:nil];


    //设置动画执行时间

    [UIView setAnimationDuration:2.0];


    //1.先取出frame

    CGRect frame = _button.frame;


    // 向下走是y值加等于 (+=) 一定要连起来写

    frame.origin.y  += 20;


    //frame的值从新赋值给_button.frame

    _button.frame = frame;


    //设置动画结束

    [UIView commitAnimations];


}


#pragma mark 向右走的实现方法

- (IBAction)right:(id)sender {


    //实现动画

    [ UIView beginAnimations:nil context:nil];


    //设置动画执行时间

    [UIView setAnimationDuration:2.0];


    // 获取frame;

    CGRect frame = self.button.frame;


    //修改x值,向右走是加等于

    frame.origin.x += 20;

     //frame的值赋值给self.button.frame;

    self.button.frame = frame;


    //设置动画结束

    [UIView commitAnimations];


}


#pragma mark 向左走的实现方法

- (IBAction)left:(id)sender {


    //实现动画

    [ UIView beginAnimations:nil context:nil];


    //设置动画执行时间

    [UIView setAnimationDuration:2.0];


    // 获取frame的值

    CGRect frame = _button.frame;


    //修改x的值

    frame.origin.x -= 20;


    // frame在赋值给 _button.frame

    _button.frame = frame;


    //设置动画结束

    [UIView commitAnimations];


}


*/

   //上下左右的的效果

- (IBAction)run:(id)sender {

    //(id)sender,是传一个参数,点击那个按钮,就传那个参数



    //实现动画

    //[ UIView beginAnimations:nil context:nil];


    //设置动画执行时间

    //[UIView setAnimationDuration:2.0];


    //这个就是调用上面代码块的block方法,把控制方向的不同代码装进去, 只有调用了下面的方法,上面才的才能用block();来把下面的方法调用成功。

    [self btnClickWithBlock :^{

        // 获取frame的值

        CGRect frame = _button.frame;


        // 控制上下左右(xy)的值,可以用if else语句,也可以用switch语句


        // if else 语句的用法


        //获得参数的值,不能用点语法sender.tag,要用get语法

        /*

         if([sender tag] == 1){

         frame.origin.y -= 20;

         }else if([sender tag] == 2){

         frame.origin.x += 20;

         }else if([sender tag] == 3){

         frame.origin.y += 20;

         }else if([sender tag] == 4){

         frame.origin.y -= 20;

         }



         // 这个20也可以拿出来,两种方式,宏定义和定义变量,这样做得目的是,如果要修改这个值,可以一步就修改了,不用在一个一个修改。宏定义要卸载引用文件的位置,可以控制整个文件,一般都写宏定义,

         //CGFloat delta = 20;


         //可以把[sender tag]提前出来,设置为变量

         NSInteger tag = [sender tag];


         if(tag == 1){

         frame.origin.y -= kdelta;

         }else if(tag == 2){

         frame.origin.x += kdelta;

         }else if(tag == 3){

         frame.origin.y += kdelta;

         }else if(tag == 4){

         frame.origin.y -= kdelta;

         }

         */



        //switch语法


        switch([sender tag]){

            case 1:

                frame.origin.y -= kdelta;

                break;

            case 2:

                frame.origin.x += kdelta;

                break;

            case 3:

                frame.origin.y += kdelta;

                break;

            case 4:

                frame.origin.x -= kdelta;

                break;

                

            default:

                break;

                

        }

        

        

        

        // frame在赋值给 _button.frame

        _button.frame = frame;



    }];




    //设置动画结束



}


#pragma mark 左右旋转

// 左右旋转的效果(封装),旋转是形变属性-transform

- (IBAction)rotate:(id)sender {

    //旋转角度用M_PI这个宏定义,PI=π,也就是180°M_PI_4这个代表4分之PI = 45°M_PI_2这个代表2分之PI = 90°M_2_PI这个表示PI的两倍=360°。如果要实现某个旋转功能,就是表示增加或者减少这个°(度数),旋转就是向右(顺时针 +)或者向左(逆时针 -) 比如想要某个向左旋转45°

    //因为形变的属性是transform,所以要用按钮来活动这个属性,两种方法,一种点语法,一种get方法

    // 旋转用这个方法CGAffineTransformMakeRotation(M_PI_4);如果在括号里面只是写一个(M_PI_4)的话,旋转也只有一次,不能累减(累加)

    //_button.transform =  CGAffineTransformMakeRotation(-M_PI_4);// 所以这个只能旋转一次,肯定不是我们最终要得效果。

    //利用另外一个函数(方法)CGAffineTransformRotate(CGAffineTransform t, CGFloat angle); 其中CGAffineTransform t是之前的角度,CGFloat angle是要旋转的角度

    [self btnClickWithBlock :^{

    //_button.transform =  CGAffineTransformMakeRotation(-M_PI_4);

    if([sender tag] == 5){ //往左

    _button.transform = CGAffineTransformRotate(_button.transform, -M_PI_4); // 这样就能够实现连续的左旋转了,但是有个小BUG,就是旋转后,点击向下移,就会从屏幕中消失(待修改)

    }else if(6 ==[sender tag]){ // 往右 //常量在前面比较好,这样如果少写一个等号,就会报错

       _button.transform = CGAffineTransformRotate(_button.transform, M_PI_4);// 这里是往右旋转,也就是+,但是这个+可写可不写

    }

}];

    //上面的写法,具有可读性,但是代码量有冗余,可以用三目运算,但是可读性不强

    //因为-M_PI_4 = M_PI_4 * -1

    //因为M_PI_4 = M_PI_4 * 1


    //_button.transform = CGAffineTransformRotate(_button.transform, -M_PI_4 * ([sender tag] == 5?1:-1));

}


#pragma mark 伸缩

- (IBAction)telescopic:(id)sender {

    //伸缩也是形变属性,所有也是用transform,然后 CGAffineTramMakeScale(CGFloat sx, CGFloat sy);这个方法CGFloat sx x的值(控制上下缩放)CGFloat syy(控制左右缩放),默认是1,如果两个值都是1,那么就不变,如果x=0.5y = 2,这样的意思是,x是之前的一半,y是之前的一倍

    //_button.transform = CGAffineTransformMakeScale(0.5, 2); // 这里碰到的结果也是一样,这样的写法也只能缩放一次,所以需要用另外一个函数(方法)CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy); 其中CGAffineTransform t 是当前的值,CGFloat sx, CGFloat sy是传进来的需要缩放的常量

    /* 这里用if语句有问题,所以应该用三目运算符

    if(7 ==[sender tag]){

    _button.transform = CGAffineTransformScale(_button.transform, 1.2, 0.8);

    }else if(8 ==[sender tag]){

        _button.transform = CGAffineTransformScale(_button.transform, 0.8, 1.2);

    }

     */

    [self btnClickWithBlock :^{


    //1.首先要把 x y值剥离出来,设置成变量 然后用三目运算符,如果tag = 7 那么就放大0.2倍,所以不等于7,就缩小

    CGFloat scale = [sender tag] == 7 ? 1.2 : 0.9;

    _button.transform = CGAffineTransformScale(_button.transform, scale, scale);

        }];

}

@end



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值