抽屉

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

  

posted @   Show撑腰  阅读(135)  评论(0编辑  收藏  举报
编辑推荐:
· 深入理解 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 构建精确任务处理应用
点击右上角即可分享
微信分享提示