如何在自定义tableview单元格中保留图像的选定状态?

时间:2014-12-21 02:57:19

标签: ios objective-c uitableview uiimageview

好的,我有新的困境。我一直在寻找S.O.找到答案,但我似乎无法得到任何代码。我也查看了许多教程和其他资源,但似乎无法找到任何帮助。

这是交易:我有一个带有自定义对象的自定义单元格的tableview。自定义单元格包含一个图像,可以选择该图像以指示是否已使用单元格中列出的运输类型。图像从灰色的"未选择的"陈述一个蓝色"选择"状态(或从#34;选择"到"未选择")。图像上的轻击手势会触发警报视图,用户可以在其中选择"是"或"不"。警报视图然后使图像更改为"选择"或"未选中"状态,基本上像一个复选标记。一切都很完美。 (我添加了警报视图,以防止图像上出现无意的敲击手势)。

http://tinypic.com/r/s5d3s3/8

当滚动期间单元格消失然后再次重新出现时,会出现问题,图像将被取消选择。很多人都问过这个问题。看起来我需要: (1)设置一个可变数组来保存选择 (2)在cellForRowAtIndexPath中执行一些检查,告诉单元格显示什么 (3)和某处,设置所选图像的状态,以便将其添加到可变数组中。

我尝试从一些给定的答案中实现想法,但很多都使用按钮或单元配件。部分问题是在哪里实现了一些代码,因为我已经在图像上触发了手势识别器和警报视图。此外,将选择保存到nsuserdefaults也会在滚动期间保持图像的状态,或者我是否需要单独处理这两个问题? (意思是,添加代码以在滚动期间保持状态以及代码以保存到nsuserdefaults)。我试过了一些S.O.使用nususerdefaults的答案,但有同样的问题...我在哪里放这个代码?如何保存图像状态而不是保存按钮状态或单元附件状态?

我还要注意,tableview嵌入在导航控制器中,并且每个单元格都会转到详细视图,这会在将代码添加到didSelectCellAtIndexPath(大多数S.O.答案包括在内)时增加问题。如何挑出被轻敲的图像而不是整个单元格(这通常会导致与图像选择一起出现segue)。

任何形式的帮助都将受到赞赏!提前谢谢你。 :)

以下是我的所有代码:

**TRANSPORT.h**

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface Transport : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) UIImage *transportImage;
@property (nonatomic, strong) UIImage *usedTransportImage;

@end


**TRANSPORTDATACONTROLLER.h**

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "Transport.h"

@interface TransportDataController : NSObject

@property (nonatomic, strong) NSMutableArray *transportDataArray;
-(NSMutableArray *)populateDataSource;

@end


**TRANSPORTDATACONTROLLER.m**

#import "TransportDataController.h"

@implementation TransportDataController

-(NSMutableArray *)populateDataSource
{
    _transportDataArray = [[NSMutableArray alloc] init];
    Transport *transportData = [[Transport alloc] init];

    transportData.name = @"Bus";
    transportData.transportImage = [UIImage imageNamed:@"Bus"];
    transportData.usedTransportImage = [UIImage imageNamed:@"stamp-grayed"];
    [_transportDataArray addObject:transportData];

    transportData = [[Transport alloc] init];
    transportData.name = @"Helicopter";
    transportData.transportImage = [UIImage imageNamed:@"Helicopter"];
    transportData.usedTransportImage = [UIImage imageNamed:@"stamp-grayed"];
    [_transportDataArray addObject:transportData];

    transportData = [[Transport alloc] init];
    transportData.name = @"Truck";
    transportData.transportImage = [UIImage imageNamed:@"Truck"];
    transportData.usedTransportImage = [UIImage imageNamed:@"stamp-grayed"];
    [_transportDataArray addObject:transportData];

    transportData = [[Transport alloc] init];
    transportData.name = @"Boat";
    transportData.transportImage = [UIImage imageNamed:@"Boat"];
    transportData.usedTransportImage = [UIImage imageNamed:@"stamp-grayed"];
    [_transportDataArray addObject:transportData];

    transportData = [[Transport alloc] init];
    transportData.name = @"Bicycle";
    transportData.transportImage = [UIImage imageNamed:@"Bicycle"];
    transportData.usedTransportImage = [UIImage imageNamed:@"stamp-grayed"];
    [_transportDataArray addObject:transportData];

    transportData = [[Transport alloc] init];
    transportData.name = @"Motorcycle";
    transportData.transportImage = [UIImage imageNamed:@"Motorcycle"];
    transportData.usedTransportImage = [UIImage imageNamed:@"stamp-grayed"];
    [_transportDataArray addObject:transportData];

    transportData = [[Transport alloc] init];
    transportData.name = @"Plane";
    transportData.transportImage = [UIImage imageNamed:@"Plane"];
    transportData.usedTransportImage = [UIImage imageNamed:@"stamp-grayed"];
    [_transportDataArray addObject:transportData];

    transportData = [[Transport alloc] init];
    transportData.name = @"Train";
    transportData.transportImage = [UIImage imageNamed:@"Train"];
    transportData.usedTransportImage = [UIImage imageNamed:@"stamp-grayed"];
    [_transportDataArray addObject:transportData];

    transportData = [[Transport alloc] init];
    transportData.name = @"Car";
    transportData.transportImage = [UIImage imageNamed:@"Car"];
    transportData.usedTransportImage = [UIImage imageNamed:@"stamp-grayed"];
    [_transportDataArray addObject:transportData];

    transportData = [[Transport alloc] init];
    transportData.name = @"Scooter";
    transportData.transportImage = [UIImage imageNamed:@"Scooter"];
    transportData.usedTransportImage = [UIImage imageNamed:@"stamp-grayed"];
    [_transportDataArray addObject:transportData];

    transportData = [[Transport alloc] init];
    transportData.name = @"Caravan";
    transportData.transportImage = [UIImage imageNamed:@"Caravan"];
    transportData.usedTransportImage = [UIImage imageNamed:@"stamp-grayed"];
    [_transportDataArray addObject:transportData];

    return _transportDataArray; 
}

@end


**TRANSPORTCELL.h**

#import <UIKit/UIKit.h>

@interface TransportCell : UITableViewCell

@property (nonatomic, weak) IBOutlet UILabel *nameLabel;
@property (nonatomic, weak) IBOutlet UIImageView *transportImageView;
@property (nonatomic, weak) IBOutlet UIImageView *grayedImageView;

@end


**MAINTABLEVIEWCONTROLLER.h**

#import <UIKit/UIKit.h>
#import "Transport.h"
#import "TransportDataController.h"
#import "DetailTableViewController.h"

@interface MainTableViewController : UITableViewController

@property (nonatomic, strong) TransportDataController *transportController;
@property (nonatomic, strong) NSMutableArray *dataSource;

@end


**MAINTABLEVIEWCONTROLLER.m**

#import "MainTableViewController.h"
#import "TransportCell.h"

@interface MainTableViewController ()

@end

@implementation MainTableViewController

-(void)viewDidLoad
{
    [super viewDidLoad];

    _transportController = [[TransportDataController alloc] init];
    self.dataSource = _transportController.populateDataSource;
    self.title = @"Transportation Types";

}

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return _dataSource.count;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"mainCell";
    TransportCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil)
    {
        cell = [[TransportCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }

    Transport *transportData = [self.dataSource objectAtIndex:indexPath.row];
    cell.nameLabel.text = transportData.name;
    cell.transportImageView.image = transportData.transportImage;
    cell.grayedImageView.image = transportData.usedTransportImage;

    UITapGestureRecognizer *grayedImageTouched = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(transportImageTapped:)];
    grayedImageTouched.numberOfTapsRequired = 1;
    [cell.grayedImageView addGestureRecognizer:grayedImageTouched];
    cell.grayedImageView.userInteractionEnabled = YES;


    return cell;
}


-(void)transportImageTapped:(UIGestureRecognizer *)gesture
{
    UIImageView *selectedImageView = (UIImageView *)[gesture view];
    UIImage *grayedImage = [UIImage imageNamed:@"stamp-grayed"];
    UIImage *darkImage = [UIImage imageNamed:@"stamp-color"];

    UIAlertController *transportAlert = [UIAlertController alertControllerWithTitle:@"Yes, it's true..." message:@"I have used this type of transport before." preferredStyle:UIAlertControllerStyleAlert];

    [transportAlert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action){

        NSLog(@"cancel");

    }]];

    [transportAlert addAction:[UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){

        if (selectedImageView.image == grayedImage)
        {
            selectedImageView.image = grayedImage;
            [selectedImageView setImage:grayedImage];

        }
        else
        {
            selectedImageView.image = darkImage;
            [selectedImageView setImage:darkImage];

        }

        if (selectedImageView.image == darkImage)
        {
            selectedImageView.image = darkImage;
            [selectedImageView setImage:darkImage];

        }
        else
        {
            selectedImageView.image = grayedImage;
            [selectedImageView setImage:grayedImage];

        }

        NSLog(@"has taken this transport before");


    }]];

    [transportAlert addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){

        if (selectedImageView.image == darkImage)
        {
            selectedImageView.image = grayedImage;
            [selectedImageView setImage:grayedImage];

        }
        else
        {
            selectedImageView.image = grayedImage;
            [selectedImageView setImage:grayedImage];
        }

        if (selectedImageView.image == grayedImage)
        {
            selectedImageView.image = grayedImage;
            [selectedImageView setImage:grayedImage];
        }

        NSLog(@"has not taken this transport before");
    }]];

    [self presentViewController:transportAlert animated:YES completion:nil];

}


-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"showDetail"])
    {
        DetailTableViewController *detailController = [segue destinationViewController];
        detailController.transport = [self.dataSource objectAtIndex:[self.tableView indexPathForSelectedRow] .row];
    }
}

@end

3 个答案:

答案 0 :(得分:2)

远离细节,思考你正在做什么。

表格视图显示有关有序集合的信息。

事物是数据模型。表视图是视图对象,视图控制器是MVC设计模式中的控制器对象。

当用户以需要进行持久更改的方式与视图交互时,控制器应记录模型中的更改并告知视图更新其外观。

然后,如果一个单元格在屏幕外滚动然后再返回屏幕,则数据源应该从数据模型中为该条目设置具有新状态的再循环单元格。

对于非分段表视图,将数据模型存储为某种数据对象的NSArray是很常见的。您可以创建自定义数据容器对象,也可以只使用字典。

我们说我们有一个自定义数据对象。

只需在数据对象中添加一个属性,告知是否使用了运输项目。

当用户点击视图对象时,视图控制器应通过更改&#34;已使用的&#34;来响应来自手势识别器的消息。特定索引路径的数据模型对象的属性,然后告诉视图重绘自己。

在你的cellForRowAtIndexPath方法中,根据&#34;的状态设置视图对象&#34;旗。由于您已将状态更改保存到数据模型中,因此下次用户在表数据中显示给定索引的单元格时,它会显示已更改的状态。

答案 1 :(得分:0)

正如您所怀疑的那样,您需要在按下按钮时更改数据源数据,以便cellForRowAtIndexPath可以正确加载所需的图像。在这种情况下,您只需将TransportCell的{​​{1}}(即与{UIGestureRecognizer绑定的usedTransportImage)更改为深色或灰色,具体取决于警报视图的输入。

正如你的代码现在所说的那样,你的警报块中的逻辑是有缺陷的,我不确定你要完成什么 - 你的“是”块总是留下你的形象,你的“没有“块总是将图像设置为灰色,并且您在每个块内重复设置图像多次。我猜你也许你想要一个“是”的回答来将UIImage设置为黑暗而将“{1}”设置为灰色(?)......所以使用这个假设作为例如,这是我的建议:

usedTransportImage

如果您希望获得关于在按下按钮时阻止视图转换的问题的第二部分的帮助,请从usedTransportImage发布您的代码。

答案 2 :(得分:0)

这是您需要做的事情,如下所示。更改了transportImageTapped方法的实现。代码未经过测试,因此可能会出现轻微错误。如果这有帮助,请告诉我。 创建一个NSMutableArray说NSMutableArray * selected;

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"mainCell";
TransportCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil)
{
    cell = [[TransportCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}

Transport *transportData = [self.dataSource objectAtIndex:indexPath.row];
cell.nameLabel.text = transportData.name;
cell.transportImageView.image = transportData.transportImage;
if([selected containsObject:indexPath]) {
    cell.grayedImageView.image = transportData.usedTransportImage;
} else {
    cell.grayedImageView.image = transportData.deSelectedTransportImage;
}

UITapGestureRecognizer *grayedImageTouched = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(transportImageTapped:)];
grayedImageTouched.numberOfTapsRequired = 1;
[cell.grayedImageView addGestureRecognizer:grayedImageTouched];
cell.grayedImageView.userInteractionEnabled = YES;


return cell;
}

-(void)transportImageTapped:(UIGestureRecognizer *)gesture
{
CGPoint point= [gesture locationInView:self.tableView];
NSIndexPath *theIndexPath = [theTableView indexPathForRowAtPoint:point];

UIAlertController *transportAlert = [UIAlertController alertControllerWithTitle:@"Yes, it's true..." message:@"I have used this type of transport before." preferredStyle:UIAlertControllerStyleAlert];

[transportAlert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action){

    NSLog(@"cancel");

}]];

[transportAlert addAction:[UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){

    if(selected containsObject:theIndexPath ) {
        //Already selected - Remove the selection
        [selected removeObject:theIndexPath];
    } else {
        // Set the object as selected
        [selected addObjetc:theIndexPath];
    }

    NSLog(@"has taken this transport before");
    NSArray* indexArray = [NSArray arrayWithObjects:theIndexPath, nil];
    // Launch reload for the two index path
    [self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];

}]];

[transportAlert addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){

    if(selected containsObject:theIndexPath ) {
        //Already selected - Remove the selection
        [selected removeObject:theIndexPath];
    } else {
        // Set the object as selected
        [selected addObjetc:theIndexPath];
    }

    NSLog(@"has not taken this transport before");
    NSArray* indexArray = [NSArray arrayWithObjects:theIndexPath, nil];
    // Launch reload for the two index path
    [self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];

}]];

[self presentViewController:transportAlert animated:YES completion:nil];

}