抽屉
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | #import "ViewController.h" // @"frame" #define keyPath(objc, keyPath) @(((void)objc.keyPath, #keyPath)) // 在宏里面如果在参数前添加了#,就会把参数变成C语言字符串 // 获取屏幕的宽度 #define screenW [UIScreen mainScreen].bounds.size.width // 获取屏幕的高度 #define screenH [UIScreen mainScreen].bounds.size.height @interface ViewController () @end @implementation ViewController - ( void )viewDidLoad { [ super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. // 添加所有的子控件 [ self setUpAllChildView]; // 添加拖拽手势 UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget: self action: @selector (pan:)]; [_mainV addGestureRecognizer:pan]; // KVO作用:时刻监听某个对象的某个属性的改变 // _main frame属性的改变 // Observer:观察者 // KeyPath:监听的属性 // NSKeyValueObservingOptionNew:表示监听新值的改变 [_mainV addObserver: self forKeyPath:XMGkeyPath(_mainV, frame) options: NSKeyValueObservingOptionNew context: nil ]; // 给控制器的view添加一个点按 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector (tap)]; [ self .view addGestureRecognizer:tap]; } - ( void )tap { if (_mainV.frame.origin.x != 0) { // 把_mainV还原最开始的位置 [UIView animateWithDuration:0.25 animations:^{ _mainV.frame = self .view.bounds; }]; } } // 只要监听的属性一改变,就会调用 - ( void )observeValueForKeyPath:( NSString *)keyPath ofObject:( id )object change:( NSDictionary *)change context:( void *)context { if (_mainV.frame.origin.x > 0) { // 往右滑动,显示左边控件,隐藏右边控件 _rightV.hidden = YES ; } else if (_mainV.frame.origin.x < 0){ // 往左滑动,显示右边控件 _rightV.hidden = NO ; } } // 注意:当对象被销毁的时候,一定要注意移除观察者 - ( void )dealloc { // 移除观察者 [_mainV removeObserver: self forKeyPath:XMGkeyPath(_mainV, frame)]; } #define targetR 300 #define targetL -200 - ( void )pan:(UIPanGestureRecognizer *)pan { // 获取手势的偏移量 CGPoint transP = [pan translationInView:_mainV]; // 获取x轴的偏移量,相对于上一次 CGFloat offsetX = transP.x; // 修改最新的main.frame, _mainV.frame = [ self frameWithOffsetX:offsetX]; // 复位 [pan setTranslation:CGPointZero inView:_mainV]; // 判断下当前手指有没有抬起,表示手势结束 if (pan.state == UIGestureRecognizerStateEnded) { // 手指抬起,定位 // x>屏幕的一半,定位到右边某个位置 CGFloat target = 0; if (_mainV.frame.origin.x > screenW * 0.5) { target = targetR; } else if (CGRectGetMaxX(_mainV.frame) < screenW * 0.5){ // 最大的x < 屏幕一半的时候,定义到左边某个位置 target = targetL; } // 获取x轴的偏移量 CGFloat offsetX = target - _mainV.frame.origin.x; [UIView animateWithDuration:0.25 animations:^{ _mainV.frame = [ self frameWithOffsetX:offsetX]; }]; } } #define XMGMaxY 100 // 给定一个x轴的偏移量计算下最新main的frame - (CGRect)frameWithOffsetX:(CGFloat)offsetX { // 获取当前main的frame CGRect frame = _mainV.frame; // 计算当前的x,y,w,h // 获取最新的x CGFloat x = frame.origin.x + offsetX; // 获取最新的y CGFloat y = x / screenW * XMGMaxY; // 当用户往左边移动的时候,_main.x < 0,y需要增加,为正 if (frame.origin.x < 0) { y = -y; } // 获取最新的h CGFloat h = screenH - 2 * y; // 获取缩放比例 CGFloat scale = h / screenH; // 获取最新的w CGFloat w = screenW * scale; return CGRectMake(x, y, w, h); } // 添加所有的子控件 - ( void )setUpAllChildView { // left UIView *leftV = [[UIView alloc] initWithFrame: self .view.bounds]; leftV.backgroundColor = [UIColor greenColor]; [ self .view addSubview:leftV]; _leftV = leftV; // right UIView *rightV = [[UIView alloc] initWithFrame: self .view.bounds]; rightV.backgroundColor = [UIColor blueColor]; [ self .view addSubview:rightV]; _rightV = rightV; // main UIView *mainV = [[UIView alloc] initWithFrame: self .view.bounds]; mainV.backgroundColor = [UIColor redColor]; [ self .view addSubview:mainV]; _mainV = mainV; } @end |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 《HelloGitHub》第 106 期
· 数据库服务器 SQL Server 版本升级公告
· 深入理解Mybatis分库分表执行原理
· 使用 Dify + LLM 构建精确任务处理应用