iOS开发基础87-抽屉效果

实现一个简单的抽屉效果:

核心思想:KVO实现监听mainV的frame值的变化

 

核心代码:

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
#import "ViewController.h"
 
// @"frame"
 
#define XMGkeyPath(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];
     
    // 添加所有的子控件
    [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 -230
 
- (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

 

用法:

继承ViewController

实现如下代码即可:

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
#import "SlideViewController.h"
 
@interface SlideViewController ()
 
@end
 
@implementation SlideViewController
 
- (void)viewDidLoad{
    [super viewDidLoad];
    NSLog(@"%s",__func__);
     
    // 创建一个tableView控制器
    UITableViewController *tableVc = [[UITableViewController alloc] init];
     
    tableVc.view.frame = self.mainV.bounds;
     
    [self.mainV addSubview:tableVc.view];
     
    // 设计原理,如果A控制器的view成为b控制器view的子控件,那么这个A控制器必须成为B控制器的子控制器
    [self addChildViewController:tableVc];
     
     
     
    UIViewController *VC = [[UIViewController alloc] init];
     
    UIImageView *imagev = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"胸小别讲话"]];
     
    //    imagev.contentMode = UIViewContentModeScaleAspectFill;
     
    imagev.frame = VC.view.frame;
     
    [VC.view addSubview:imagev];
     
    [self.rightV addSubview:VC.view];
     
    [self addChildViewController:VC];
     
     
     
     
}
 
@end

 github地址:https://github.com/chglog/drawer

posted @   Mr.陳  阅读(2169)  评论(0编辑  收藏  举报
编辑推荐:
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示