From 6df35a9d231febb65ed5e10da2a26cb1b76e1a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=AE=AA=E4=BA=AE?= Date: Wed, 8 Jan 2020 09:58:22 +0800 Subject: [PATCH] 666 --- XLChannelControl/XLChannelControl.h | 19 +++ XLChannelControl/XLChannelControl.m | 79 +++++++++ XLChannelControl/XLChannelHeader.h | 17 ++ XLChannelControl/XLChannelHeader.m | 58 +++++++ XLChannelControl/XLChannelItem.h | 21 +++ XLChannelControl/XLChannelItem.m | 111 +++++++++++++ XLChannelControl/XLChannelView.h | 19 +++ XLChannelControl/XLChannelView.m | 242 ++++++++++++++++++++++++++++ 8 files changed, 566 insertions(+) create mode 100644 XLChannelControl/XLChannelControl.h create mode 100644 XLChannelControl/XLChannelControl.m create mode 100644 XLChannelControl/XLChannelHeader.h create mode 100644 XLChannelControl/XLChannelHeader.m create mode 100644 XLChannelControl/XLChannelItem.h create mode 100644 XLChannelControl/XLChannelItem.m create mode 100644 XLChannelControl/XLChannelView.h create mode 100644 XLChannelControl/XLChannelView.m diff --git a/XLChannelControl/XLChannelControl.h b/XLChannelControl/XLChannelControl.h new file mode 100644 index 0000000..bdfc15f --- /dev/null +++ b/XLChannelControl/XLChannelControl.h @@ -0,0 +1,19 @@ +// +// XLChannelControl.h +// XLChannelControlDemo +// +// Created by MengXianLiang on 2017/3/3. +// Copyright © 2017年 MengXianLiang. All rights reserved. +// + +#import + +typedef void(^XLChannelBlock)(NSArray *enabledTitles,NSArray *disabledTitles); + +@interface XLChannelControl : NSObject + ++ (XLChannelControl*)shareControl; + +- (void)showChannelViewWithEnabledTitles:(NSArray*)enabledTitles disabledTitles:(NSArray*)disabledTitles finish:(XLChannelBlock)block; + +@end diff --git a/XLChannelControl/XLChannelControl.m b/XLChannelControl/XLChannelControl.m new file mode 100644 index 0000000..47ef6e8 --- /dev/null +++ b/XLChannelControl/XLChannelControl.m @@ -0,0 +1,79 @@ +// +// XLChannelControl.m +// XLChannelControlDemo +// +// Created by MengXianLiang on 2017/3/3. +// Copyright © 2017年 MengXianLiang. All rights reserved. +// + +#import "XLChannelControl.h" +#import "XLChannelView.h" + +@interface XLChannelControl () + +@property (nonatomic, strong) UINavigationController *nav; + +@property (nonatomic, strong) XLChannelView *channelView; + +@property (nonatomic, strong) XLChannelBlock block; + +@end + +@implementation XLChannelControl + ++(XLChannelControl*)shareControl{ + static XLChannelControl *control = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + control = [[XLChannelControl alloc] init]; + }); + return control; +} + +- (instancetype)init { + if (self = [super init]) { + [self buildChannelView]; + } + return self; +} + +- (void)buildChannelView { + + self.channelView = [[XLChannelView alloc] initWithFrame:[UIScreen mainScreen].bounds]; + + self.nav = [[UINavigationController alloc] initWithRootViewController:[UIViewController new]]; + self.nav.navigationBar.tintColor = [UIColor blackColor]; + self.nav.topViewController.title = @"频道管理"; + self.nav.topViewController.view = self.channelView; + self.nav.topViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop target:self action:@selector(backMethod)]; +} + +- (void)backMethod { + [UIView animateWithDuration:0.3 animations:^{ + CGRect frame = self.nav.view.frame; + frame.origin.y = - self.nav.view.bounds.size.height; + self.nav.view.frame = frame; + }completion:^(BOOL finished) { + [self.nav.view removeFromSuperview]; + }]; + self.block(self.channelView.enabledTitles,self.channelView.disabledTitles); +} + +- (void)showChannelViewWithEnabledTitles:(NSArray*)enabledTitles disabledTitles:(NSArray*)disabledTitles finish:(XLChannelBlock)block { + self.block = block; + self.channelView.enabledTitles = [NSMutableArray arrayWithArray:enabledTitles]; + self.channelView.disabledTitles = [NSMutableArray arrayWithArray:disabledTitles]; + [self.channelView reloadData]; + + CGRect frame = self.nav.view.frame; + frame.origin.y = - self.nav.view.bounds.size.height; + self.nav.view.frame = frame; + self.nav.view.alpha = 0; + [[UIApplication sharedApplication].keyWindow addSubview:self.nav.view]; + [UIView animateWithDuration:0.3 animations:^{ + self.nav.view.alpha = 1; + self.nav.view.frame = [UIScreen mainScreen].bounds; + }]; +} + +@end diff --git a/XLChannelControl/XLChannelHeader.h b/XLChannelControl/XLChannelHeader.h new file mode 100644 index 0000000..ea39f58 --- /dev/null +++ b/XLChannelControl/XLChannelHeader.h @@ -0,0 +1,17 @@ +// +// XLChannelHeaderView.h +// XLChannelControlDemo +// +// Created by MengXianLiang on 2017/3/3. +// Copyright © 2017年 MengXianLiang. All rights reserved. +// + +#import + +@interface XLChannelHeader : UICollectionReusableView + +@property (copy,nonatomic) NSString *title; + +@property (copy,nonatomic) NSString *subTitle; + +@end diff --git a/XLChannelControl/XLChannelHeader.m b/XLChannelControl/XLChannelHeader.m new file mode 100644 index 0000000..c9c412b --- /dev/null +++ b/XLChannelControl/XLChannelHeader.m @@ -0,0 +1,58 @@ +// +// XLChannelHeaderView.m +// XLChannelControlDemo +// +// Created by MengXianLiang on 2017/3/3. +// Copyright © 2017年 MengXianLiang. All rights reserved. +// + +#import "XLChannelHeader.h" + +@interface XLChannelHeader () + +@property (nonatomic, strong) UILabel *titleLabel; + +@property (nonatomic, strong) UILabel *subtitleLabel; + +@end + +@implementation XLChannelHeader + +-(instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + [self buildUI]; + } + return self; +} + +-(void)buildUI +{ + CGFloat marginX = 15.0f; + + CGFloat labelWidth = (self.bounds.size.width - 2*marginX)/2.0f; + + self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(marginX, 0, labelWidth, self.bounds.size.height)]; + self.titleLabel.textColor = [UIColor blackColor]; + [self addSubview:self.titleLabel]; + + self.subtitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelWidth + marginX, 0, labelWidth, self.bounds.size.height)]; + self.subtitleLabel.textColor = [UIColor lightGrayColor]; + self.subtitleLabel.textAlignment = NSTextAlignmentRight; + self.subtitleLabel.font = [UIFont systemFontOfSize:15.0f]; + [self addSubview:self.subtitleLabel]; +} + +-(void)setTitle:(NSString *)title +{ + _title = title; + self.titleLabel.text = title; +} + +-(void)setSubTitle:(NSString *)subTitle +{ + _subTitle = subTitle; + self.subtitleLabel.text = subTitle; +} + +@end diff --git a/XLChannelControl/XLChannelItem.h b/XLChannelControl/XLChannelItem.h new file mode 100644 index 0000000..7754733 --- /dev/null +++ b/XLChannelControl/XLChannelItem.h @@ -0,0 +1,21 @@ +// +// XLChannelItem.h +// XLChannelControlDemo +// +// Created by MengXianLiang on 2017/3/3. +// Copyright © 2017年 MengXianLiang. All rights reserved. +// + +#import + +@interface XLChannelItem : UICollectionViewCell +//标题 +@property (nonatomic, copy) NSString *title; + +//是否正在移动状态 +@property (nonatomic, assign) BOOL isMoving; + +//是否被固定 +@property (nonatomic, assign) BOOL isFixed; + +@end diff --git a/XLChannelControl/XLChannelItem.m b/XLChannelControl/XLChannelItem.m new file mode 100644 index 0000000..703a6ec --- /dev/null +++ b/XLChannelControl/XLChannelItem.m @@ -0,0 +1,111 @@ +// +// XLChannelItem.m +// XLChannelControlDemo +// +// Created by MengXianLiang on 2017/3/3. +// Copyright © 2017年 MengXianLiang. All rights reserved. +// + +#import "XLChannelItem.h" + +@interface XLChannelItem () + +@property (nonatomic, strong) UILabel *textLabel; + +@property (nonatomic, strong) CAShapeLayer *borderLayer; + +@end + +@implementation XLChannelItem + +-(instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + [self initUI]; + } + return self; +} + +-(void)initUI +{ + self.userInteractionEnabled = true; + self.layer.cornerRadius = 5.0f; + self.backgroundColor = [self backgroundColor]; + + self.textLabel = [UILabel new]; + self.textLabel.frame = self.bounds; + self.textLabel.textAlignment = NSTextAlignmentCenter; + self.textLabel.textColor = [self textColor]; + self.textLabel.adjustsFontSizeToFitWidth = true; + self.textLabel.userInteractionEnabled = true; + [self addSubview:self.textLabel]; + + [self addBorderLayer]; +} + +-(void)addBorderLayer{ + self.borderLayer = [CAShapeLayer layer]; + self.borderLayer.bounds = self.bounds; + self.borderLayer.position = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)); + self.borderLayer.path = [UIBezierPath bezierPathWithRoundedRect:self.borderLayer.bounds cornerRadius:self.layer.cornerRadius].CGPath; + self.borderLayer.lineWidth = 1; + self.borderLayer.lineDashPattern = @[@5, @3]; + self.borderLayer.fillColor = [UIColor clearColor].CGColor; + self.borderLayer.strokeColor = [self backgroundColor].CGColor; + [self.layer addSublayer:self.borderLayer]; + self.borderLayer.hidden = true; +} + +-(void)layoutSubviews +{ + [super layoutSubviews]; + self.textLabel.frame = self.bounds; +} + +#pragma mark - +#pragma mark 配置方法 + +-(UIColor*)backgroundColor{ + return [UIColor colorWithRed:241/255.0f green:241/255.0f blue:241/255.0f alpha:1]; +} + +-(UIColor*)textColor{ + return [UIColor colorWithRed:40/255.0f green:40/255.0f blue:40/255.0f alpha:1]; +} + +-(UIColor*)lightTextColor{ + return [UIColor colorWithRed:200/255.0f green:200/255.0f blue:200/255.0f alpha:1]; +} + +#pragma mark - +#pragma mark Setter + +-(void)setTitle:(NSString *)title +{ + _title = title; + self.textLabel.text = title; +} + +-(void)setIsMoving:(BOOL)isMoving +{ + _isMoving = isMoving; + if (_isMoving) { + self.backgroundColor = [UIColor clearColor]; + self.borderLayer.hidden = false; + }else{ + self.backgroundColor = [self backgroundColor]; + self.borderLayer.hidden = true; + } +} + +-(void)setIsFixed:(BOOL)isFixed{ + _isFixed = isFixed; + if (isFixed) { + self.textLabel.textColor = [self lightTextColor]; + }else{ + self.textLabel.textColor = [self textColor]; + } +} + +@end diff --git a/XLChannelControl/XLChannelView.h b/XLChannelControl/XLChannelView.h new file mode 100644 index 0000000..1b0603c --- /dev/null +++ b/XLChannelControl/XLChannelView.h @@ -0,0 +1,19 @@ +// +// XLChannelView.h +// XLChannelControlDemo +// +// Created by MengXianLiang on 2017/3/3. +// Copyright © 2017年 MengXianLiang. All rights reserved. +// + +#import + +@interface XLChannelView : UIView + +@property (nonatomic, strong) NSMutableArray *enabledTitles; + +@property (nonatomic,strong) NSMutableArray *disabledTitles; + +-(void)reloadData; + +@end diff --git a/XLChannelControl/XLChannelView.m b/XLChannelControl/XLChannelView.m new file mode 100644 index 0000000..429c834 --- /dev/null +++ b/XLChannelControl/XLChannelView.m @@ -0,0 +1,242 @@ +// +// XLChannelView.m +// XLChannelControlDemo +// +// Created by MengXianLiang on 2017/3/3. +// Copyright © 2017年 MengXianLiang. All rights reserved. +// + +#import "XLChannelView.h" +#import "XLChannelItem.h" +#import "XLChannelHeader.h" + +//菜单列数 +static NSInteger ColumnNumber = 4; +//横向和纵向的间距 +static CGFloat CellMarginX = 15.0f; +static CGFloat CellMarginY = 10.0f; + + +@interface XLChannelView () + +@property (nonatomic, strong) UICollectionView *collectionView; + +@property (nonatomic, strong) XLChannelItem *dragingItem; + +@property (nonatomic, strong) NSIndexPath *dragingIndexPath; + +@property (nonatomic, strong) NSIndexPath *targetIndexPath; + +@end + +@implementation XLChannelView + +- (instancetype)initWithFrame:(CGRect)frame{ + if (self = [super initWithFrame:frame]) { + [self buildUI]; + } + return self; +} + +-(void)buildUI{ + self.backgroundColor = [UIColor whiteColor]; + + UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init]; + CGFloat cellWidth = (self.bounds.size.width - (ColumnNumber + 1) * CellMarginX)/ColumnNumber; + flowLayout.itemSize = CGSizeMake(cellWidth,cellWidth/2.0f); + flowLayout.sectionInset = UIEdgeInsetsMake(CellMarginY, CellMarginX, CellMarginY, CellMarginX); + flowLayout.minimumLineSpacing = CellMarginY; + flowLayout.minimumInteritemSpacing = CellMarginX; + flowLayout.headerReferenceSize = CGSizeMake(self.bounds.size.width, 40); + + self.collectionView = [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:flowLayout]; + self.collectionView.showsHorizontalScrollIndicator = false; + self.collectionView.backgroundColor = [UIColor clearColor]; + [self.collectionView registerClass:[XLChannelItem class] forCellWithReuseIdentifier:@"XLChannelItem"]; + [self.collectionView registerClass:[XLChannelHeader class] + forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"XLChannelHeader"]; + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + [self addSubview:self.collectionView]; + + UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressMethod:)]; + longPress.minimumPressDuration = 0.3f; + [self.collectionView addGestureRecognizer:longPress]; + + self.dragingItem = [[XLChannelItem alloc] initWithFrame:CGRectMake(0, 0, cellWidth, cellWidth/2.0f)]; + self.dragingItem.hidden = true; + [self.collectionView addSubview:self.dragingItem]; +} + +#pragma mark - +#pragma mark LongPressMethod +-(void)longPressMethod:(UILongPressGestureRecognizer*)gesture{ + CGPoint point = [gesture locationInView:self.collectionView]; + switch (gesture.state) { + case UIGestureRecognizerStateBegan: + [self dragBegin:point]; + break; + case UIGestureRecognizerStateChanged: + [self dragChanged:point]; + break; + case UIGestureRecognizerStateEnded: + [self dragEnd]; + break; + default: + break; + } +} + +//拖拽开始 找到被拖拽的item +-(void)dragBegin:(CGPoint)point{ + self.dragingIndexPath = [self getDragingIndexPathWithPoint:point]; + if (!self.dragingIndexPath) {return;} + [self.collectionView bringSubviewToFront:self.dragingItem]; + XLChannelItem *item = (XLChannelItem*)[self.collectionView cellForItemAtIndexPath:self.dragingIndexPath]; + item.isMoving = true; + //更新被拖拽的item + self.dragingItem.hidden = false; + self.dragingItem.frame = item.frame; + self.dragingItem.title = item.title; + [self.dragingItem setTransform:CGAffineTransformMakeScale(1.1, 1.1)]; +} + +//正在被拖拽、、、 +-(void)dragChanged:(CGPoint)point{ + if (!self.dragingIndexPath) {return;} + self.dragingItem.center = point; + self.targetIndexPath = [self getTargetIndexPathWithPoint:point]; + //交换位置 如果没有找到self.targetIndexPath则不交换位置 + if (self.dragingIndexPath && self.targetIndexPath) { + //更新数据源 + [self rearrangeInUseTitles]; + //更新item位置 + [self.collectionView moveItemAtIndexPath:self.dragingIndexPath toIndexPath:self.targetIndexPath]; + self.dragingIndexPath = self.targetIndexPath; + } +} + +//拖拽结束 +-(void)dragEnd{ + if (!self.dragingIndexPath) {return;} + CGRect endFrame = [self.collectionView cellForItemAtIndexPath:self.dragingIndexPath].frame; + [self.dragingItem setTransform:CGAffineTransformMakeScale(1.0, 1.0)]; + [UIView animateWithDuration:0.3 animations:^{ + self.dragingItem.frame = endFrame; + }completion:^(BOOL finished) { + self.dragingItem.hidden = true; + XLChannelItem *item = (XLChannelItem*)[self.collectionView cellForItemAtIndexPath:self.dragingIndexPath]; + item.isMoving = false; + }]; +} + +#pragma mark - +#pragma mark 辅助方法 + +//获取被拖动IndexPath的方法 +-(NSIndexPath*)getDragingIndexPathWithPoint:(CGPoint)point{ + NSIndexPath* dragIndexPath = nil; + //最后剩一个怎不可以排序 + if ([self.collectionView numberOfItemsInSection:0] == 1) {return dragIndexPath;} + for (NSIndexPath *indexPath in self.collectionView.indexPathsForVisibleItems) { + //下半部分不需要排序 + if (indexPath.section > 0) {continue;} + //在上半部分中找出相对应的Item + if (CGRectContainsPoint([self.collectionView cellForItemAtIndexPath:indexPath].frame, point)) { + if (indexPath.row != 0) { + dragIndexPath = indexPath; + } + break; + } + } + return dragIndexPath; +} + +//获取目标IndexPath的方法 +-(NSIndexPath*)getTargetIndexPathWithPoint:(CGPoint)point{ + NSIndexPath *targetIndexPath = nil; + for (NSIndexPath *indexPath in self.collectionView.indexPathsForVisibleItems) { + //如果是自己不需要排序 + if ([indexPath isEqual:self.dragingIndexPath]) {continue;} + //第二组不需要排序 + if (indexPath.section > 0) {continue;} + //在第一组中找出将被替换位置的Item + if (CGRectContainsPoint([self.collectionView cellForItemAtIndexPath:indexPath].frame, point)) { + if (indexPath.row != 0) { + targetIndexPath = indexPath; + } + } + } + return targetIndexPath; +} + +#pragma mark - +#pragma mark CollectionViewDelegate&DataSource +-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section +{ + return section == 0 ? self.enabledTitles.count : self.disabledTitles.count; +} + +-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView +{ + return 2; +} + +- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath +{ + XLChannelHeader *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"XLChannelHeader" forIndexPath:indexPath]; + if (indexPath.section == 0) { + headerView.title = @"已选频道"; + headerView.subTitle = @"按住拖动调整排序"; + }else{ + headerView.title = @"推荐频道"; + headerView.subTitle = @""; + } + return headerView; +} + + +-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString* cellId = @"XLChannelItem"; + XLChannelItem* item = [collectionView dequeueReusableCellWithReuseIdentifier:cellId forIndexPath:indexPath]; + item.title = indexPath.section == 0 ? self.enabledTitles[indexPath.row] : self.disabledTitles[indexPath.row]; + item.isFixed = indexPath.section == 0 && indexPath.row == 0; + return item; +} + +-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath +{ + if (indexPath.section == 0) { + //只剩一个的时候不可删除 + if ([self.collectionView numberOfItemsInSection:0] == 1) {return;} + //第一个不可删除 + if (indexPath.row == 0) {return;} + id obj = [self.enabledTitles objectAtIndex:indexPath.row]; + [self.enabledTitles removeObject:obj]; + [self.disabledTitles insertObject:obj atIndex:0]; + [self.collectionView moveItemAtIndexPath:indexPath toIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]]; + }else{ + id obj = [self.disabledTitles objectAtIndex:indexPath.row]; + [self.disabledTitles removeObject:obj]; + [self.enabledTitles addObject:obj]; + [self.collectionView moveItemAtIndexPath:indexPath toIndexPath:[NSIndexPath indexPathForRow:self.enabledTitles.count - 1 inSection:0]]; + } +} + +#pragma mark - +#pragma mark 刷新方法 +//拖拽排序后需要重新排序数据源 +-(void)rearrangeInUseTitles +{ + id obj = [self.enabledTitles objectAtIndex:self.dragingIndexPath.row]; + [self.enabledTitles removeObject:obj]; + [self.enabledTitles insertObject:obj atIndex:self.targetIndexPath.row]; +} + +-(void)reloadData +{ + [self.collectionView reloadData]; +} + +@end