随意细解:UI -- 设计模式、手势识别

本文详细介绍了UI设计中的target/Action模式和代理模式,强调了这些模式的主要目标是解耦并提高代码复用性。同时,文章还探讨了在实现点击事件时如何遵循MVC设计模式。此外,文章涵盖了UIGestureRecognizer的各种手势识别,包括轻拍、长按、旋转、捏合、平移、轻扫和边缘扫等,展示了如何在实际应用中添加和响应这些手势。

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

target/Action设计模式

举例:点击view实现点击功能,改变背景颜色(类似button的addtarget方法)

创建ButtonView,遵守协议:

在ButtonView.h中:为了方便调用,声明成属性

@property (nonatomic, retain) id target;
@property (nonatomic, assign) SEL action;
            // 初始化方法
- (instancetype)initWithFrame:(CGRect)frame target:(id)target action:(SEL)action; 

在ButtonView.m中:

- (void)dealloc
{
    [self.target release];
    [super dealloc];
}

- (instancetype)initWithFrame:(CGRect)frame target:(id)target action:(SEL)action
{
    self = [super initWithFrame:frame];
    if (self) {
     // 初始化时,对属性进行赋值
    self.target = target;
    self.action = action;

     }
    return self;
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
        // 使用self.target对象调用 action方法
        // 让一个对象 去调用这个对象类里的方法
        // Object 可携带的参数
        [self.target performSelector:self.action withObject:self];
}

创建RootViewController作为根控制器

- (void)viewDidLoad {
    [super viewDidLoad];
    ButtonView *buttonView = [[ButtonView alloc]initWithFrame:CGRectMake(100, 100, 100, 100) target:self action:@selector(buttonClick:)];
    buttonView.backgroundColor = [UIColor redColor];
    [self.view addSubview:buttonView];
    [buttonView release];
}
- (void)buttonClick:(ButtonView *)buttonView
{
     buttonView.backgroundColor = [UIColor blackColor];
     NSLog(@"触发了");
}

delegate代理模式

不管是target/Action设计模式,代理设计模式还是 MVC设计模式,中心只有一个,解耦,提高代码的复用性。

举例说明:点击ImageView,实现点击事件,改变背景颜色,并且遵循MVC设计模式

  1. 创建 ButtonImageView,并创建协议

    在@interface之前声明协议,因为需要类本身作为参数,所以使用@class方法告诉文件,ButtonImageView是一个类:(ButtonImageView.h文件中)

    @class ButtonImageView;
    @protocol  ButtonImageViewDElegate <NSObject>
    
    - (void)ButtonImageViewClick:(ButtonImageView *)imageView;
    
    @end
    
  2. 设置代理

    需要调用ButtonImageView的代理方法,所以将delegate设置为属性:(ButtonImageView.h文件中)

    @property (nonatomic, assign) id<ButtonImageViewDElegate> delegate;
    

    代理属性为什么要声明成assign?

    防止循环引用从而造成的内存泄露。解释:

     假如 A是B的代理,B也是A的代理,如果是 retain
     [[A alloc]init];      A:1
     [[B alloc]init];      B:1
     A.delegate = B;       B:2
     B.delegate = A;       A:2
     [A release];          A:1
     [B release];          B:1
     A和B的引用计数都是1,无法释放,造成内存泄露。
    
  3. 实现 touchesEnded 方法:(ButtonImageView.m文件中)
    注:声明delegate属性,需要重写dealloc方法

    - (void)dealloc
    {
        [self.delegate release];
        [super dealloc];
    }
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
        // 判断保护,判断delegateshif响应点击方法
        if ([_delegate respondsToSelector:@selector(ButtonImageViewClick:)]) {
            // 调用代理方法
            [_delegate ButtonImageViewClick:self];
        }
    }
    
  4. 创建MyView , 调用ButtonImageView

    为了外部可以直接调用imageView,将imageView声明称属性:(在MyView.h中)

    // 引入头文件
    #import "ButtonImageView.h"
    
    // 声明属性
    @property (nonatomic, retain) ButtonImageView *imageView;
    
  5. 在MyView中重写initWithFrame方法

    - (void)dealloc
    {
        [self.imageView release];
        [super dealloc];
    }
    
    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            self.imageView = [[ButtonImageView alloc]initWithFrame:[UIScreen mainScreen].bounds];
            [self addSubview:self.imageView];
            [self.imageView release];
        }
        return self;
    }
    
  6. 创建 RootViewController ,作为根控制器。遵循协议(在RootViewController.h文件中)

    // 引入头文件
    #import "ButtonImageView.h"
    @interface RootViewController : UIViewController <ButtonImageViewDElegate>
    
  7. 实现协议中的方法

    - (void)viewDidLoad {
        [super viewDidLoad];
        MyView *myView = [[MyView alloc]initWithFrame:[UIScreen mainScreen].bounds];
        // 设置代理
        myView.imageView.delegate = self;
        self.view = myView;
        [myView release];
    }
    // 实现协议中的方法
    - (void)ButtonImageViewClick:(ButtonImageView *)imageView
    {
        imageView.backgroundColor = [UIColor yellowColor];
    }
    

手势识别

手势类 UIGestureRecognizer,这个类是个抽象类,其具体功能交给子类去实现。

创建ImageView,添加手势:

    UIImageView *imageView = [[UIImageView alloc]initWithFrame:[UIScreen mainScreen].bounds];
    [self.view addSubview:imageView];
    imageView.image = [UIImage imageNamed:@"C8"];
    // 打开交互
    imageView.userInteractionEnabled = YES;
    [imageView release];
  • 轻拍

viewDidLoad方法中:

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapAction:)];
    // 添加手势到视图上
    [imageView addGestureRecognizer:tap];
    [tap release];

实现轻拍方法

    - (void)tapAction:(UITapGestureRecognizer *)tap
    {
           UIImageView *imageView = (UIImageView *)tap.view;
            imageView.image = [UIImage imageNamed:@"C1"];
            NSLog(@"你拍我了");
    }
  • 长按

viewDidLoad方法中:

    UILongPressGestureRecognizer *longPress= [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPressAction:)];
    // 设置长按时间
    longPress.minimumPressDuration = 2.0;
    // 添加到视图上
    [imageView addGestureRecognizer:longPress];
    [longPress release];

实现长按方法

    - (void)longPressAction:(UILongPressGestureRecognizer *)longPress
    {
    // 判断一下手势状态,长按,只需要触发一次
        if (longPress.state == UIGestureRecognizerStateBegan) {
            NSLog(@"长按触发了多少次?");
            UIImageView *imageView = (UIImageView *)longPress.view;
            imageView.image = [UIImage imageNamed:@"image.jpg"];
            NSLog(@"你按我了");
        }
    }
  • 旋转

viewDidLoad方法中:

        UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotationAction:)];

    [imageView addGestureRecognizer:rotation];
    [rotation release];

实现旋转方法

    - (void)rotationAction:(UIRotationGestureRecognizer *)rotation
    {
        // 形变属性 transform
        // 参数1:改变形变属性的视图
        // 参数2:根据弧度去创建
        rotation.view.transform = CGAffineTransformRotate(rotation.view.transform, rotation.rotation);
        // 每次转需要把旋转的角度重置为0
        // 因为要接替上一次的角度 开始旋转
        rotation.rotation = 0;
        NSLog(@"旋转了");
    }
  • 捏合

viewDidLoad方法中:

    UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinchAction:)];
    [imageView addGestureRecognizer:pinch];
    [pinch release];

实现捏合方法

    - (void)pinchAction:(UIPinchGestureRecognizer *)pinch
    {
        // 根据缩放的刻度(比例)改变形变属性
        // 根据捏合的比较,去改变形变属性
        pinch.view.transform = CGAffineTransformScale(pinch.view.transform, pinch.scale , pinch.scale);
        // 重置捏合的比例
        pinch.scale = 1;
        NSLog(@"捏合");
    }
  • 平移

viewDidLoad方法中:

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panAction:)];
    [imageView addGestureRecognizer:pan];
    [pan release];

实现平移方法

    - (void)panAction:(UIPanGestureRecognizer *)pan
    {
        // 获取平移的点(相对于要平移的视图)
        CGPoint p = [pan translationInView:pan.view];
        // 根据这个点改变形变属性
        pan.view.transform = CGAffineTransformTranslate(pan.view.transform, p.x, p.y);
        // 重置这个点
        [pan setTranslation:CGPointMake(0, 0) inView:pan.view];
        NSLog(@"平移");
    }
  • 轻扫

viewDidLoad方法中:

    UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeAction:)];
    // 设置左右扫的方向
    swipe.direction = UISwipeGestureRecognizerDirectionLeft;

    [imageView addGestureRecognizer:swipe];
    [swipe release];

实现轻扫方法

    - (void)swipeAction:(UISwipeGestureRecognizer *)swipe
    {

        NSLog(@"左扫");
    }
  • 边缘扫

viewDidLoad方法中:

    UIScreenEdgePanGestureRecognizer *screenEdgePan = [[UIScreenEdgePanGestureRecognizer alloc]initWithTarget:self action:@selector(screenEdgePanAction:)];
    // 设置从哪个边缘开始扫
    screenEdgePan.edges = UIRectEdgeRight;
    [imageView addGestureRecognizer:screenEdgePan];
    [screenEdgePan release];

实现边缘扫方法

    - (void)screenEdgePanAction:(UIScreenEdgePanGestureRecognizer *)screenEdgePan
    {
        NSLog(@"边缘扫一定要靠近屏幕边缘开始扫");
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值