内容简介:级别: ★☆☆☆☆标签:「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(微信公众号)
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 自定义控件神器--PathMeasure
- Qt编写自定义控件20-自定义饼图 原 荐
- 【PyQT5】自定义控件 显示网络图片
- [译]自定义控件教程: 可复用的 Slider
- iOS 自定义卡片式控件:QiCardView
- Angular 使用 ControlValueAccessor 创建自定义表单控件
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。