内容简介:级别: ★☆☆☆☆标签:「iOS」「拖拽式控件」「QiDragView」作者:MrLiuQ
级别: ★☆☆☆☆
标签:「iOS」「拖拽式控件」「QiDragView」
作者:MrLiuQ
审校:QiShare团队
首先,我们先看一下QiDragView的效果图:
一、QiDragView整体架构设计
话不多说,上架构图~
QiDragView(QiDragSortView的简称)是一种可选择可拖拽的自定义控件,可以满足一些拖拽 排序 的业务需求场景。
二、如何自定义使用QiDragView?
在上Demo之前,先介绍几个可以自定义的UI配置属性:
| 属性 | 类型 | 介绍 |
|---|---|---|
| rowHeight | CGFloat | 行高 |
| rowMargin | CGFloat | 行边距 |
| rowPadding | CGFloat | 行间距 |
| columnMargin | CGFloat | 列边距 |
| columnPadding | CGFloat | 列间距 |
| columnCount | NSInteger | 列数 |
| normalColor | UIColor | 按钮基本字体颜色 |
| selectedColor | UIColor | 按钮选择字体颜色 |
以及一些逻辑配置属性:
| 属性 | 类型 | 介绍 |
|---|---|---|
| enabledTitles | NSArray<NSString *> | 可以 被点击 的titles(上行参数,默认全选) |
| selectedTitles | NSArray<NSString *> | 可以 被选择 的titles(上行参数,默认全选) |
| titles | NSArray<NSString *> | 按钮的 titles (上行参数,会根据titles,创建出对应的button) |
使用起来也很方便:
dragSortEnded
默认配置用法:
QiDragSortView *dragSortView = [[QiDragSortView alloc] initWithFrame:CGRectMake(.0, 100.0, self.view.bounds.size.width, .0)];
dragSortView.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:.5];
dragSortView.titles = @[@"首页推荐", @"奇舞周刊", @"众成翻译", @"QiShare", @"HULK一线杂谈", @"Qtest之道"];//!< 初始的Buttons(必填)
[self.view addSubview:dragSortView];
//! 拖拽方法回调:能拿到Button数组的排序和选择状态
dragSortView.dragSortEnded = ^(NSArray<UIButton *> * _Nonnull buttons) {
for (UIButton *button in buttons) {
NSLog(@"title: %@, selected: %i", button.currentTitle, button.isSelected);
}
};
复制代码
自定义配置用法:
QiDragSortView *dragSortView = [[QiDragSortView alloc] initWithFrame:CGRectMake(.0, 100.0, self.view.bounds.size.width, .0)];
dragSortView.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:.5];
dragSortView.rowHeight = 50.0;
dragSortView.rowMargin = 30.0;
dragSortView.rowPadding = 20.0;
dragSortView.columnCount = 3;
dragSortView.columnMargin = 30.0;
dragSortView.columnPadding = 20.0;
dragSortView.normalColor = [UIColor redColor];
dragSortView.selectedColor = [UIColor purpleColor];
dragSortView.enabledTitles = @[@"奇舞周刊", @"众成翻译", @"QiShare", @"HULK一线杂谈", @"Qtest之道"];//!< 可以点击选择的Buttons(选填,默认全选)
dragSortView.selectedTitles = @[@"首页推荐", @"HULK一线杂谈", @"Qtest之道"];//!< 初始选择的Buttons(选填,默认全选)
dragSortView.titles = @[@"首页推荐", @"奇舞周刊", @"众成翻译", @"QiShare", @"HULK一线杂谈", @"Qtest之道"];//!< 初始的Buttons(必填)
[self.view addSubview:dragSortView];
//! 拖拽方法回调:能拿到Button数组的排序和选择状态
dragSortView.dragSortEnded = ^(NSArray<UIButton *> * _Nonnull buttons) {
for (UIButton *button in buttons) {
NSLog(@"title: %@, selected: %i", button.currentTitle, button.isSelected);
}
};
复制代码
三、QiDragView的技术点
3.1 长按手势:
长按手势分别对应三种状态: UIGestureRecognizerStateBegan 、 UIGestureRecognizerStateChanged 、 UIGestureRecognizerStateEnded 。
| 状态 | 说明 |
|---|---|
| UIGestureRecognizerStateBegan | 长按手势 开始 |
| UIGestureRecognizerStateChanged | 长按手势 拖拽中 (进行时) |
| UIGestureRecognizerStateEnded | 长按手势 结束 |
//! 长按手势
- (void)longPress:(UILongPressGestureRecognizer *)gesture {
UIButton *currentButton = (UIButton *)gesture.view;
if (gesture.state == UIGestureRecognizerStateBegan) {
[self bringSubviewToFront:currentButton];
[UIView animateWithDuration:.25 animations:^{
self.originButtonCenter = currentButton.center;
self.originGesturePoint = [gesture locationInView:currentButton];
currentButton.transform = CGAffineTransformScale(currentButton.transform, 1.2, 1.2);
}];
}
else if (gesture.state == UIGestureRecognizerStateEnded) {
[UIView animateWithDuration:.25 animations:^{
currentButton.center = self.originButtonCenter;
currentButton.transform = CGAffineTransformIdentity;
} completion:^(BOOL finished) {
if (self.dragSortEnded) {
self.dragSortEnded(self.buttons);
}
}];
}
else if (gesture.state == UIGestureRecognizerStateChanged) {
CGPoint gesturePoint = [gesture locationInView:currentButton];
CGFloat deltaX = gesturePoint.x - _originGesturePoint.x;
CGFloat deltaY = gesturePoint.y - _originGesturePoint.y;
currentButton.center = CGPointMake(currentButton.center.x + deltaX, currentButton.center.y + deltaY);
NSInteger fromIndex = currentButton.tag;
NSInteger toIndex = [self toIndexWithCurrentButton:currentButton];
if (toIndex >= 0) {
currentButton.tag = toIndex;
if (toIndex > fromIndex) {
for (NSInteger i = fromIndex; i < toIndex; i++) {
UIButton *nextButton = _buttons[i + 1];
CGPoint tempPoint = nextButton.center;
[UIView animateWithDuration:.5 animations:^{
nextButton.center = self.originButtonCenter;
}];
_originButtonCenter = tempPoint;
nextButton.tag = i;
}
}
else if (toIndex < fromIndex) {
for (NSInteger i = fromIndex; i > toIndex; i--) {
UIButton *previousButton = self.buttons[i - 1];
CGPoint tempPoint = previousButton.center;
[UIView animateWithDuration:.5 animations:^{
previousButton.center = self.originButtonCenter;
}];
_originButtonCenter = tempPoint;
previousButton.tag = i;
}
}
[_buttons sortUsingComparator:^NSComparisonResult(UIButton *obj1, UIButton *obj2) {
return obj1.tag > obj2.tag;
}];
}
}
}
复制代码
3.2 配置按钮:
设计思路:在属性titles的 setter 方法中,初始化并配置好各个Buttons。
- (void)setTitles:(NSArray<NSString *> *)titles {
_titles = titles;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSInteger differCount = titles.count - self.buttons.count;
if (differCount > 0) {
for (NSInteger i = self.buttons.count; i < titles.count; i++) {
[self.buttons addObject:[self buttonWithTag:i]];
}
}
else if (differCount < 0) {
NSArray *extraButtons = [self.buttons subarrayWithRange:(NSRange){titles.count, self.buttons.count - titles.count}];
[self.buttons removeObjectsInArray:extraButtons];
for (UIButton *button in extraButtons) {
[button removeFromSuperview];
}
}
self.enabledTitles = self.enabledTitles ?: titles;//!< 如果有,就传入,否则传入titles
self.selectedTitles = self.selectedTitles ?: titles;
for (NSInteger i = 0; i < self.buttons.count; i++) {
[self.buttons[i] setTitle:titles[i] forState:UIControlStateNormal];
[self.buttons[i] addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)]];//!< 长按手势
[self selectButton:self.buttons[i] forStatus:[self.selectedTitles containsObject:titles[i]]];
if ([self.enabledTitles containsObject:titles[i]]) {
[self.buttons[i] addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
}
}
for (NSInteger i = 0; i < self.buttons.count; i++) {
NSInteger rowIndex = i / self.columnCount;
NSInteger columnIndex = i % self.columnCount;
CGFloat buttonWidth = (self.bounds.size.width - self.columnMargin * 2 - self.columnPadding * (self.columnCount - 1)) / self.columnCount;
CGFloat buttonX = self.columnMargin + columnIndex * (buttonWidth + self.columnPadding);
CGFloat buttonY = self.rowMargin + rowIndex * (self.rowHeight + self.rowPadding);
self.buttons[i].frame = CGRectMake(buttonX, buttonY, buttonWidth, self.rowHeight);
}
CGRect frame = self.frame;
NSInteger rowCount = ceilf((CGFloat)self.buttons.count / (CGFloat)self.columnCount);
frame.size.height = self.rowMargin * 2 + self.rowHeight * rowCount + self.rowPadding * (rowCount - 1);
self.frame = frame;
});
}
复制代码
源码地址: QiDragView
小编微信:可加并拉入《QiShare技术交流群》。
关注我们的途径有:
QiShare(微信公众号)
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Iterative Methods for Sparse Linear Systems, Second Edition
Yousef Saad / Society for Industrial and Applied Mathematics / 2003-04-30 / USD 102.00
Tremendous progress has been made in the scientific and engineering disciplines regarding the use of iterative methods for linear systems. The size and complexity of linear and nonlinear systems arisi......一起来看看 《Iterative Methods for Sparse Linear Systems, Second Edition》 这本书的介绍吧!