Obj-C- 在不重新加载整个 collectionView 的情况下更新 UICollectionView 数据?

Obj-C- Update UICollectionView data without reloading entire collectionView?

我有一个 UICollectionView,当单元格被选中时,它们会变成用户选择的颜色。绘制完整图片:颜色由用户从色轮 (UIImageView) 中选择,并带有点击手势。

就是说,当用户在选择 3 个单元格并将它们变为绿色后点击一种新颜色,比如紫色(并重置定义的 rString、bString 和 gString...)时,我想重新加载它们的颜色使用而不擦除 Collection View 中最初选择的 3 个绿色单元格。我怎样才能做到这一点?

请参阅下面的代码。

ViewController.m

  @interface ViewController () {
        
        CGPoint lastPoint;
        NSInteger rString;
        NSInteger bString;
        NSInteger gString;
        UIColor *colour;
        
    }
    
    @property (strong, nonatomic, nullable) NSIndexPath *trackingCellIndexPath;
    
    
    @end
    
    @implementation ViewController
    
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
      
        self.ringCollectionView.allowsMultipleSelection = YES;
    
    UITapGestureRecognizer * tapRecognizer = [[UITapGestureRecognizer alloc] 
     initWithTarget:self action:@selector(tapGesture:)];
     [self.colorWheel addGestureRecognizer:tapRecognizer];
     self.colorWheel.userInteractionEnabled = YES;

    }
    
    - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        
        UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"RingCollectionViewCell" forIndexPath:indexPath];
     
        if (!cell.selectedBackgroundView) {
            cell.selectedBackgroundView = [[UIView alloc] initWithFrame:cell.bounds];
                   cell.selectedBackgroundView.backgroundColor = [UIColor grayColor];
        } else {
            cell.selectedBackgroundView = [[UIView alloc] initWithFrame:cell.bounds];
            cell.selectedBackgroundView.backgroundColor = [UIColor colorWithRed:rString/255.0 green:gString/255.0 blue:bString/255.0 alpha:1.0];
            
        }
      
        
        if ((indexPath.row >=9 && indexPath.row <=14) || ((indexPath.row >=17 && indexPath.row < 23) || (indexPath.row >=25 && indexPath.row <=30) ||  (indexPath.row >=33 && indexPath.row <=38))) {
            
            NSLog(@"NOT AVAILABLE SORRY");
            cell.backgroundColor = [UIColor whiteColor];
            
            [cell setUserInteractionEnabled:NO];
            
        }
    
            return cell;
       
    
    }
    
    
    -(void)tapGesture:(UITapGestureRecognizer *)recognizer  {
        
        CGPoint location = [recognizer locationInView:recognizer.view];
        CGPoint p = { round(location.x), round(location.y) };
        _colorView.backgroundColor = [self colorInViewAtPoint:p];
        
       
        UIColor *mylovelycolor = [self colorInViewAtPoint:p];
         
      
           const CGFloat *components = CGColorGetComponents(mylovelycolor.CGColor);
           NSLog(@"Red: %f", components[0]);
           NSLog(@"Green: %f", components[1]);
           NSLog(@"Blue: %f", components[2]);
           NSLog(@"Alpha: %f", CGColorGetAlpha(mylovelycolor.CGColor));
           
    
               int red = components[0] * 255;
               int green = components[1] * 255;
               int blue = components[2] * 255;
           
               NSString *red1 = [@(red) stringValue];
               NSString *green1 = [@(green) stringValue];
               NSString *blue1 = [@(blue) stringValue];
               
               
               NSInteger redInt = [red1 integerValue];
               NSInteger greenInt = [green1 integerValue];
               NSInteger blueInt = [blue1 integerValue];
               
                 rString = [red1 integerValue];
                 bString = [blue1 integerValue];
                 gString =  [green1 integerValue];
        
    
                self.redValue.text = red1;
                self.greenValue.text = green1;
                self.blueValue.text = blue1;
        
                
                        NSMutableString *str1 = [NSMutableString string];
                        for(NSInteger numberCopy = redInt; numberCopy > 0; numberCopy >>= 1)
                        {
                         
                            [str1 insertString:((numberCopy & 1) ? @"1" : @"0") atIndex:0];
                        }
    
                      
                        NSMutableString *str2 = [NSMutableString string];
                        for(NSInteger numberCopy = greenInt; numberCopy > 0; numberCopy >>= 1)
                        {
                         
                            [str2 insertString:((numberCopy & 1) ? @"1" : @"0") atIndex:0];
                        }
    
                     
                        NSMutableString *str3 = [NSMutableString string];
                        for(NSInteger numberCopy = blueInt; numberCopy > 0; numberCopy >>= 1)
                        {
                           
                            [str3 insertString:((numberCopy & 1) ? @"1" : @"0") atIndex:0];
                        }
    
        
                        self.binaryString = [NSString stringWithFormat:@" %@ %@ %@", str1, str2, str3];
        
    }

您需要在数据模型中跟踪用户select编辑的颜色。

cellForItemAtIndexPath 中,您想将单元格的背景颜色(或您正在使用的任何元素)设置为 数据元素 颜色。

当用户select编辑了一个或多个单元格并点击您的“colorWheel”时,更新您的数据模型,然后直接设置单元格元素或重新加载这些单元格。

这是一个非常简单的例子...

MyDataObject.h

//
//  MyDataObject.h
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface MyDataObject : NSObject
@property (strong, nonatomic) UIColor *userColor;
@end

NS_ASSUME_NONNULL_END

MyDataObject.m

//
//  MyDataObject.m
//

#import "MyDataObject.h"

@implementation MyDataObject

@end

MyCollectionViewCell.h

//
//  MyCollectionViewCell.h
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface MyCollectionViewCell : UICollectionViewCell
@property (strong, nonatomic) UILabel *label;
@end

NS_ASSUME_NONNULL_END

MyCollectionViewCell.m

//
//  MyCollectionViewCell.m
//

#import "MyCollectionViewCell.h"

@implementation MyCollectionViewCell

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self commonInit];
    }
    return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
        [self commonInit];
    }
    return self;
}
- (void)commonInit {
    _label = [UILabel new];
    _label.textAlignment = NSTextAlignmentCenter;
    _label.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0];
    _label.translatesAutoresizingMaskIntoConstraints = NO;
    [self.contentView addSubview:_label];

    UILayoutGuide *g = [self.contentView layoutMarginsGuide];
    [NSLayoutConstraint activateConstraints:@[
        [_label.widthAnchor constraintEqualToAnchor:g.widthAnchor multiplier:0.8],
        [_label.heightAnchor constraintEqualToAnchor:g.heightAnchor multiplier:0.8],
        [_label.centerXAnchor constraintEqualToAnchor:g.centerXAnchor],
        [_label.centerYAnchor constraintEqualToAnchor:g.centerYAnchor],
    ]];
    self.contentView.layer.borderColor = [UIColor yellowColor].CGColor;
}
- (void)setSelected:(BOOL)selected {
    [super setSelected:selected];
    self.contentView.layer.borderWidth = selected ? 2 : 0;
}
@end

MyTestViewController.h

//
//  MyTestViewController.h
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface MyTestViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate>

@end

NS_ASSUME_NONNULL_END

MyTestViewController.m

//
//  MyTestViewController.m
//

#import "MyTestViewController.h"
#import "MyCollectionViewCell.h"
#import "MyDataObject.h"

@interface MyTestViewController ()
{
    NSMutableArray <MyDataObject *>*myCellData;
    UICollectionView *collectionView;
}
@end

@implementation MyTestViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    UICollectionViewFlowLayout *fl = [UICollectionViewFlowLayout new];
    fl.itemSize = CGSizeMake(50, 50);
    fl.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    
    collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:fl];
    collectionView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:collectionView];
    
    UILayoutGuide *g = [self.view safeAreaLayoutGuide];
    [NSLayoutConstraint activateConstraints:@[
        [collectionView.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:20.0],
        [collectionView.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:-20.0],
        [collectionView.heightAnchor constraintEqualToConstant:240.0],
        [collectionView.centerYAnchor constraintEqualToAnchor:g.centerYAnchor],
    ]];
    
    // a few color views to tap, and an
    //  "Instructions" label
    UILabel *label = [UILabel new];
    label.text = @"Tap a color to change the selected cells:";
    
    UIStackView *stack = [UIStackView new];
    
    NSArray *colors = @[
        [UIColor redColor],
        [UIColor greenColor],
        [UIColor blueColor],
        [UIColor systemYellowColor],
        [UIColor systemTealColor],
    ];
    
    for (UIColor *c in colors) {
        UIView *v = [UIView new];
        v.backgroundColor = c;
        UITapGestureRecognizer *t = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(gotTap:)];
        [v addGestureRecognizer:t];
        [stack addArrangedSubview:v];
    }
    
    stack.spacing = 20.0;
    stack.distribution = UIStackViewDistributionFillEqually;
    
    label.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:label];
    
    stack.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:stack];
    
    [NSLayoutConstraint activateConstraints:@[
        [stack.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:20.0],
        [stack.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:-20.0],
        [stack.bottomAnchor constraintEqualToAnchor:g.bottomAnchor constant:-20.0],
        [stack.heightAnchor constraintEqualToConstant:40.0],

        [label.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:20.0],
        [label.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:-20.0],
        [label.bottomAnchor constraintEqualToAnchor:stack.topAnchor constant:-4.0],
    ]];

    collectionView.dataSource = self;
    collectionView.delegate = self;
    
    collectionView.allowsMultipleSelection = YES;
    
    [collectionView registerClass:MyCollectionViewCell.class forCellWithReuseIdentifier:@"c"];
    
    // create 50 objects for our data
    myCellData = [NSMutableArray new];
    for (int i = 0; i < 50; i++) {
        MyDataObject *obj = [MyDataObject new];
        obj.userColor = [UIColor redColor];
        [myCellData addObject:obj];
    }
    
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return myCellData.count;
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    
    // dequeue a cell
    MyCollectionViewCell *c = (MyCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"c" forIndexPath:indexPath];
    
    // get the data object
    MyDataObject *obj = (MyDataObject *)[myCellData objectAtIndex:indexPath.item];
    
    // set cell's contentView.backgroundColor to the data object's .userColor
    c.contentView.backgroundColor = obj.userColor;
    
    // set the cell's label text
    c.label.text = [NSString stringWithFormat:@"%ld", indexPath.item];
    
    return c;

}

- (void)gotTap:(UITapGestureRecognizer *)g {
    
    if (collectionView.indexPathsForSelectedItems.count == 0) {
        UIAlertController * alert = [UIAlertController
                                     alertControllerWithTitle:@"Error"
                                     message:@"No cells are selected!"
                                     preferredStyle:UIAlertControllerStyleAlert];
        
        UIAlertAction* okButton = [UIAlertAction
                                   actionWithTitle:@"OK"
                                   style:UIAlertActionStyleDefault
                                   handler:^(UIAlertAction * action) {
        }];
        
        [alert addAction:okButton];
        
        [self presentViewController:alert animated:YES completion:nil];

        return;
    }
    
    UIView *v = g.view;
    if (v) {
        // get the background color from the tapped view
        UIColor *color = v.backgroundColor;
        
        // loop through selected cells
        for (NSIndexPath *p in collectionView.indexPathsForSelectedItems) {
            
            // update the object in our data
            [myCellData objectAtIndex:p.item].userColor = color;
            
            // get a reference to the cell
            MyCollectionViewCell *c = (MyCollectionViewCell *)[collectionView cellForItemAtIndexPath:p];
            
            // set its background color
            c.contentView.backgroundColor = color;
            
            // if we want to auto-deselect the cells
            [collectionView deselectItemAtIndexPath:p animated:YES];
        }
    }
}

@end

所以,

  • 我们的数据对象只有一个 属性:userColor
  • 我们的单元格 class 有一个居中的标签
  • 我们的控制器
    • 创建水平滚动集合视图
    • 创建一个包含 50 个数据对象的数组,默认 userColor 为红色
    • 添加 5 个颜色视图到 select

当一个单元格被 selected 时,它会用黄色勾勒出来。当点击颜色视图时,我们:

  • 更新当前 selected 单元格的数据模型
  • 设置当前 selected 单元格的 contentView 的背景颜色
  • deselect 当前 selected 单元格

看起来像这样:

然后我们 select 单元格 5、9、14:

点击绿色视图:

然后我们 select 单元格 16、17、18:

点击蓝色视图:

然后我们稍微滚动一下 select 单元格 17、21、24、25、26:

点击黄色视图:

等等。