• 关于iOS自定义控件:在view上实现事件和代理


    • 自定义控件.h

    #import <UIKit/UIKit.h>

    #import "PPViewtouchesBeginDelegate.h"

    @interface PPView : UIView

    // 这样写避免了内存泄露的问题

    @property (nonatomic, strong)UIView *Pview;

    // 保存鼠标点击在父视图上的位置和子视图的偏移量

    @property (nonatomic, assign)CGPoint plusPoint;

    // 接收传递过来的方法和对象:在touchesBegin时使用该对象调用该包装的方法

    @property (nonatomic, strong)id sender;

    @property (nonatomic, assign)SEL action;

    // 代码加载完毕,通过方法实现保存了该对象和需要调用的SEL

    - (void)addTarget:(id)target andAction:(SEL)action;

    // 点击view显示字符串

    @property (nonatomic, strong)NSString *PPText;

    // 限定合适的代理(弱引用):触发是view被点击时

    @property (nonatomic, weak)id<PPViewtouchesBeginDelegate> delegate;

    @end


    • 自定义控件代理

    #import <Foundation/Foundation.h>

    // 谁成为我的代理,谁就属于了我的类型:反向传值(代理应用_2)

    @class PPView;

    @protocol PPViewtouchesBeginDelegate <NSObject>

    // - 确保传递出去的形参可以访问属性:谁触发就把谁传递出去

    - (void)touchesPPVoewBegin:(PPView *)sender;

    @end


    •  自定义控件.m

    #import "PPView.h"

    @implementation PPView

    // 1.在原view基础上添加了一个view:每次创建自定义view就会自带一个添加了的view

    - (instancetype)initWithFrame:(CGRect)frame

    {

        // - 让该视图在被创建的父视图的中央

        if (self = [super initWithFrame:frame])

        {

            // > 父类初始化成功后才给子类的frame赋值

            CGFloat width = self.frame.size.width;

            CGFloat height = self.frame.size.height;

            

            // > 需要创建对象

            _Pview = [[UIView alloc] initWithFrame:CGRectMake(width/4, height/4, width/2, height/2)];

            _Pview.backgroundColor = [UIColor purpleColor];

            

            // > 在传递过来的父视图上添加主视图,而不是在主视图上:self.view

            [self addSubview:_Pview];

        }

        return self;

    }

    // 2.让添加的view能在父视图上移动

    // - 基于原来的位置移动,而不是把view的center带到了鼠标点击的位置

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

    {

        // > 先记录下点击当前视图的位置

        

        // * 获取点击的位置的坐标:通过方法传递过来的形参获取

         CGPoint clickPoint = [[touches anyObject] locationInView:self];

        

        // * 获取的坐标是相同的

        //[[touches anyObject] previousLocationInView:self];

        

        // > 保存主视图的中心点和鼠标点击位置的差值

        _plusPoint.x = _Pview.center.x - clickPoint.x;

        _plusPoint.y = _Pview.center.y - clickPoint.y;

        

       

        // 3.通过保存的对象和SEL:在touchesBegin时使用该对象调用该包装的方法

        // 注意:是调用被打包的方法,即点击view后传递过来的方法;而不是该类中自定义的事件

        [self.sender performSelector:self.action];

        

        

        // 4.代理:在点击view时让view显示属性(字符串):系统的TouchesBegin事件触发时

        // - 判断代理是否为空

        if (self.delegate!=nil)

        {

            // 判断代理是否实现了协议内方法

            if ([self.delegate respondsToSelector:@selector(touchesPPVoewBegin:)])

            {

                // >复合是思想:代理被使用代理的类所复合,通过代理调用了代理遵循的方法

                // > 确保传递出去的形参可以访问属性:谁触发就把谁传递出去

                [self.delegate touchesPPVoewBegin:self];

            }

        }else

        {

            NSLog(@"delegate = nil");

        }

        

    }

    // - 让鼠标的移动和子视图的距离变得固定

    - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

    {

        CGPoint clickPoint = [[touches anyObject] locationInView:self];

        // > 保存鼠标点击父视图上的位置:这个值是不断变化的

        _Pview.center = (CGPoint){clickPoint.x+_plusPoint.x, clickPoint.y+_plusPoint.y};

    }

    // 3.在view上实现了button的效果

    // - 触发事件时就保存了传递过来的对象和被打包的方法

    - (void)addTarget:(id)target andAction:(SEL)action

    {

        // - 代码加载完毕,通过方法实现保存了该对象和需要调用的SEL

        self.sender = target;

        self.action = action;

        

    }


  • 相关阅读:
    SQL 查询第n条到第m条的数据
    Linq 中查询一个表中指定的字段
    归并排序与逆序对
    补码拾遗
    堆排序
    It is time to cut the Gordian Knot!
    蛋疼
    [引]Microsoft Visual Studio .NET 2005 预发行版
    关于VS2005中自动生成TableAdapter的事务处理
    关于释放ASPNET进程的内存占用问题.
  • 原文地址:https://www.cnblogs.com/pruple/p/5267530.html
Copyright © 2020-2023  润新知