- 自定義控件.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;
}