UITableView 多个部分,带有 GUI 元素 UIButton、UISwitch 等

Posted

技术标签:

【中文标题】UITableView 多个部分,带有 GUI 元素 UIButton、UISwitch 等【英文标题】:UITableView multiple sections with GUI Elements UIButton, UISwitch, etc 【发布时间】:2011-10-25 20:52:43 【问题描述】:

我已经在这个问题上绞尽脑汁了一天左右...我已经搜索了这个论坛以及谷歌和其他博客等。都无济于事。

我正在做的是创建一个包含多个部分的UITableView,并且在每个部分中,每一行都有不同的 GUI 元素(即设置屏幕)

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
    return 3;

我想要实现的只是每个部分在不同的单元格中都有不同的 GUI 元素。但是正如您在此屏幕截图中看到的那样:

最初一切都按原样显示,但在向上和向下滚动一次后,问题就开始了。元素开始四处移动,向上和向下滚动的次数越多/时间越长,元素移动的次数就越多。

!["UITableView 在部分和行中带有 GUI 元素。错误?故障?无知?"][2]

这是一个错误吗?毛刺?还是无知? (可能是后者)-我已经删除了除 GUI 代码之外的所有其他代码,如果它意味着任何我正在使用 NIB 创建UITableView

另外,这是我的cellForRowAtIndexPath 方法的代码。如果有人能指出我正确的方向或告诉我我做错了什么,我将永远感激不尽。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    


    // Set up the cell
    // desired section
    if(indexPath.section == 0) 
        //
        //  Load Settings
        //

        // button
        UIButton * loadButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        loadButton.frame = CGRectMake(0.0, 0.0, 300.0, 44.0);
        [loadButton setTitle:@"Load Image" forState:UIControlStateNormal];
        [loadButton setTitle:@"Load Image" forState:UIControlStateSelected];
        [loadButton addTarget:self action:@selector(loadImage:) forControlEvents:UIControlEventTouchUpInside];
        [cell.contentView addSubview:loadButton]; 


     else if(indexPath.section == 1) 
        //
        //  Mode Settings
        //
        if(indexPath.row == 0) 
            cell.text = [mode objectAtIndex:indexPath.row];    
         else if(indexPath.row == 1) 
            cell.text = [mode objectAtIndex:indexPath.row];    
        


     else if(indexPath.section == 2) 
        //
        //  Marker Settings
        //

        if(indexPath.row == 0) 
            // description text
            cell.text = [marker objectAtIndex:indexPath.row];    

            // switch
            UISwitch *markerSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
            cell.accessoryView = markerSwitch;
            [markerSwitch setOn:YES animated:NO];
            [markerSwitch addTarget:self action:@selector(markerToggle:) forControlEvents:UIControlEventValueChanged];
            [markerSwitch release];       

         else if(indexPath.row == 1) 
            UISlider *markerGridSlider = [[UISlider alloc] initWithFrame:CGRectMake(0.0, 10.0, 284, 10.0)];
            cell.accessoryView = markerGridSlider;
            markerGridSlider.minimumValueImage = [UIImage imageNamed:@"size_icon_1x1.png"];
            markerGridSlider.maximumValueImage = [UIImage imageNamed:@"size_icon_8x8.png"];

            [markerGridSlider setMinimumValue:1.0];
            [markerGridSlider setMaximumValue:8.0];
            markerGridSlider.value = 8.0;
            [markerGridSlider addTarget:self action:@selector(markerGrid:) forControlEvents:UIControlEventValueChanged];
            [markerGridSlider release];       

         else if(indexPath.row == 2) 
            UISlider *markerSpacingSlider = [[UISlider alloc] initWithFrame:CGRectMake(0.0, 10.0, 284, 10.0)];
            cell.accessoryView = markerSpacingSlider;
            markerSpacingSlider.minimumValueImage = [UIImage imageNamed:@"spacing_icon_min.png"];
            markerSpacingSlider.maximumValueImage = [UIImage imageNamed:@"spacing_icon_max.png"];

            [markerSpacingSlider setMinimumValue:1.0];
            [markerSpacingSlider setMaximumValue:(320.0/8.0)];
            markerSpacingSlider.value = 1.0;
            [markerSpacingSlider addTarget:self action:@selector(markerSpacing:) forControlEvents:UIControlEventValueChanged];
            [markerSpacingSlider release];       
        
    

    return cell;

谢谢。


非常感谢您的帮助。

也许我不明白你的意思,但我认为我已经正确地实施了你的建议。但是我仍然得到元素交换位置的故障,尽管现在经过大约 5 次以上的向上和向下滑动并且我的 UISwitch 现在被放置在左上角。

这是我更新的代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) 
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];



        if([indexPath section] == 0) 
            //
            // Load Settings
            //

            // button
            UIButton *loadButton = [[UIButton buttonWithType:UIButtonTypeRoundedRect] autorelease];
            loadButton.frame = CGRectMake(0.0, 0.0, 300.0, 44.0);
            [loadButton addTarget:self action:@selector(loadImage:) forControlEvents:UIControlEventTouchUpInside];
            [loadButton setTag:1000];

            [cell.contentView addSubview:loadButton]; 

         



        if([indexPath section] == 1) 
            //
            // Mode Settings
            //
            if([indexPath row] == 0) 
                cell.text = [mode objectAtIndex:[indexPath row]];    
            
            if([indexPath row] == 1) 
                cell.text = [mode objectAtIndex:[indexPath row]];    
            
         



        if([indexPath section] == 2) 
            //
            // Marker Settings
            //
            if([indexPath row] == 0) 
                // switch
                UISwitch *markerSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
                [markerSwitch setOn:YES animated:NO];
                [markerSwitch addTarget:self action:@selector(markerToggle:) forControlEvents:UIControlEventValueChanged];
                [markerSwitch setTag:3000];

                [cell.contentView addSubview:markerSwitch]; 
                [markerSwitch release];

            
            if([indexPath row] == 1) 
                // slider
                UISlider *markerGridSlider = [[UISlider alloc] initWithFrame:CGRectMake(0.0, 10.0, 284, 10.0)];
                markerGridSlider.minimumValueImage = [UIImage imageNamed:@"size_icon_1x1.png"];
                markerGridSlider.maximumValueImage = [UIImage imageNamed:@"size_icon_8x8.png"];

                [markerGridSlider setMinimumValue:1.0];
                [markerGridSlider setMaximumValue:8.0];
                [markerGridSlider setValue:8.0];
                [markerGridSlider addTarget:self action:@selector(markerGrid:) forControlEvents:UIControlEventValueChanged];
                [markerGridSlider setTag:3100];

                [cell.contentView addSubview:markerGridSlider]; 
                [markerGridSlider release];

            
            if([indexPath row] == 2) 
                // slider
                UISlider *markerSpacingSlider = [[UISlider alloc] initWithFrame:CGRectMake(0.0, 10.0, 284, 10.0)];
                markerSpacingSlider.minimumValueImage = [UIImage imageNamed:@"spacing_icon_min.png"];
                markerSpacingSlider.maximumValueImage = [UIImage imageNamed:@"spacing_icon_max.png"];

                [markerSpacingSlider setMinimumValue:1.0];
                [markerSpacingSlider setMaximumValue:(320.0/8.0)];
                [markerSpacingSlider setValue:1.0];
                [markerSpacingSlider addTarget:self action:@selector(markerSpacing:) forControlEvents:UIControlEventValueChanged];
                [markerSpacingSlider setTag:3200];

                [cell.contentView addSubview:markerSpacingSlider]; 
                [markerSpacingSlider release];

            
        


     // end cell == nil


    // Load
    UIButton *loadButton = (UIButton*)[cell.contentView viewWithTag:1000];
    [loadButton setTitle:@"Load Image" forState:UIControlStateNormal];
    [loadButton setTitle:@"Load Image" forState:UIControlStateSelected];

    // Mode

    // Marker
    UISwitch *markerSwitch = (UISwitch*)[cell.contentView viewWithTag:3000];
    UISlider *markerGridSlider = (UISlider*)[cell.contentView viewWithTag:3100];
    UISlider *markerSpacingSlider = (UISlider*)[cell.contentView viewWithTag:3200];


    return cell;

【问题讨论】:

【参考方案1】:

ios 中绑定到 UITable 的所有单元格都是可重用。 这就是为什么您首先使用函数调用“dequeueReusableCellWithIdentifier”获取单元格的原因,该单元格可能不是零,指向之前加载的单元格。在您的情况下,即使单元格不为零,您也可以向其中添加子视图。当您上下滚动时,这将无限次发生。

这是一个小例子:

-(int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
    return 2;


-(UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    static NSString* CellIdentifier = @"Cell";

    const NSInteger lblTag = 101;
    const NSInteger btnTag = 102;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    //First init the cells
    if (cell == nil) 
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

        //Initialize subviews of cells only in this block.

        if (indexPath.row == 0) 
            //Only the first cell on the top has a UILabel
            UILabel *lbl = [[[UILabel alloc] initWithFrame:CGRectMake(5, 5, 100, 20)] autorelease];
            lbl.tag = lblTag;    
            [cell.contentView addSubview:lbl];
         else if (indexPath.row == 1) 
            //Only the 2nd cell has a UIButton
            UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
            btn.frame = CGRectMake(5, 5, 60, 20);
            btn.tag = btnTag;    
            [cell.contentView addSubview:btn];
        
    

    //Modify your cells here
    if (indexPath.row == 0) 
        //Only the first cell on the top has a UILabel
        UILabel *lbl = (UILabel*)[cell.contentView viewWithTag:lblTag];
        //Do stuff with our label

        lbl.text = [NSString stringWithFormat:@"%d",indexPath.row];

     else if (indexPath.row == 1) 
        //Only the 2nd cell has a UIButton
        UIButton *btn = (UIButton*)[cell.contentView viewWithTag:btnTag];
        //Do stuff with our button
        [btn setTitle:[NSString stringWithFormat:@"%d",indexPath.row] forState:UIControlStateNormal];

    

    return cell;


在您的非常特定情况下,您会这样写-

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 

    if (section == 0) 
        return 1;
     else if (section == 1) 
        return 2;
     else if (section == 2) 
        return 3;
     else 
        return 0;
    


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

    static NSString *CellIdentifier = @"Cell";



    const NSInteger
    sec0BtnTag = 101,
    markerSwitchTag = 102,
    markerGridSliderTag = 103,
    markerSpacingSliderTag = 104;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];



        if([indexPath section] == 0) 
            //
            // Load Settings
            //

            // button
            UIButton *loadButton = [[UIButton buttonWithType:UIButtonTypeRoundedRect] autorelease];
            loadButton.frame = CGRectMake(0.0, 0.0, 300.0, 44.0);
            [loadButton addTarget:self action:@selector(loadImage:) forControlEvents:UIControlEventTouchUpInside];
            [loadButton setTag:sec0BtnTag];

            [cell.contentView addSubview:loadButton]; 

         



        else if([indexPath section] == 2) 
            //
            // Marker Settings
            //
            if([indexPath row] == 0) 
                // switch
                UISwitch *markerSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
                [markerSwitch setOn:YES animated:NO];
                [markerSwitch addTarget:self action:@selector(markerToggle:) forControlEvents:UIControlEventValueChanged];
                [markerSwitch setTag:markerSwitchTag];

                [cell.contentView addSubview:markerSwitch]; 
                [markerSwitch release];

            
            else if([indexPath row] == 1) 
                // slider
                UISlider *markerGridSlider = [[UISlider alloc] initWithFrame:CGRectMake(0.0, 10.0, 284, 10.0)];
                markerGridSlider.minimumValueImage = [UIImage imageNamed:@"size_icon_1x1.png"];
                markerGridSlider.maximumValueImage = [UIImage imageNamed:@"size_icon_8x8.png"];

                [markerGridSlider setMinimumValue:1.0];
                [markerGridSlider setMaximumValue:8.0];
                [markerGridSlider setValue:8.0];
                [markerGridSlider addTarget:self action:@selector(markerGrid:) forControlEvents:UIControlEventValueChanged];
                [markerGridSlider setTag:markerGridSliderTag];

                [cell.contentView addSubview:markerGridSlider]; 
                [markerGridSlider release];

            
            else if([indexPath row] == 2) 
                // slider
                UISlider *markerSpacingSlider = [[UISlider alloc] initWithFrame:CGRectMake(0.0, 10.0, 284, 10.0)];
                markerSpacingSlider.minimumValueImage = [UIImage imageNamed:@"spacing_icon_min.png"];
                markerSpacingSlider.maximumValueImage = [UIImage imageNamed:@"spacing_icon_max.png"];

                [markerSpacingSlider setMinimumValue:1.0];
                [markerSpacingSlider setMaximumValue:(320.0/8.0)];
                [markerSpacingSlider setValue:1.0];
                [markerSpacingSlider addTarget:self action:@selector(markerSpacing:) forControlEvents:UIControlEventValueChanged];
                [markerSpacingSlider setTag:markerSpacingSliderTag];

                [cell.contentView addSubview:markerSpacingSlider]; 
                [markerSpacingSlider release];

            
        


     // end cell == nil

    //Load specific cell row values

    if([indexPath section] == 0) 
        //
        // Load Settings
        //

        // button
        UIButton *loadButton = (UIButton*)[cell.contentView viewWithTag:sec0BtnTag];
        [loadButton setTitle:@"Load Image" forState:UIControlStateNormal];
        [loadButton setTitle:@"Load Image" forState:UIControlStateSelected];
        //do other stuff with the button here according to the specific row & section

     



    if([indexPath section] == 1) 
        //
        // Mode Settings
        //
        if([indexPath row] == 0) 
            cell.text = [mode objectAtIndex:[indexPath row]];    
        
        if([indexPath row] == 1) 
            cell.text = [mode objectAtIndex:[indexPath row]];    
        
     



    if([indexPath section] == 2) 
        //
        // Marker Settings
        //
        if([indexPath row] == 0) 
            // switch
            UISwitch *markerSwitch = (UISwitch*)[cell.contentView viewWithTag:markerSwitchTag];
            //do stuff with the switch here according to the specific row & section
        
        if([indexPath row] == 1) 
            // slider
            UISlider *markerGridSlider = (UISlider*)[cell.contentView viewWithTag:markerGridSliderTag];
            //do stuff with the slider here according to the specific row & section
        
        if([indexPath row] == 2) 
            // slider
            UISlider *markerSpacingSlider = (UISlider*)[cell.contentView viewWithTag:markerSpacingSliderTag];
            //do stuff with the slider here according to the specific row & section



        
    


    return cell;

【讨论】:

好的。我可能不完全理解你的意思。虽然我认为我已经实施了你的建议。大约需要 5 次以上的 UP 和 DOWN 才能恢复故障,但它仍然存在。 修改了我的答案。请参阅包含的示例。【参考方案2】:

为每个部分更改 static NSString *CellIdentifier = @"Cell";,例如:

NSString *CellIdentifier; if(indexPath.section==0) CellIdentifier= @"Cell"; elseif(indexPath.section==2) CellIdentifier=@"Cell2";

【讨论】:

以上是关于UITableView 多个部分,带有 GUI 元素 UIButton、UISwitch 等的主要内容,如果未能解决你的问题,请参考以下文章

带有 NSFetchedResultsController 的 UITableView 为没有对象的部分保留标题

标题选择 UITableview 中的多个部分

UIScrollview有一个大视图,还是带有多个视图的UITableview?

无论如何创建一个带有一个通用页脚的 UITableView 吗?

如何滚动uitableview和顶部的部分标题,可见并滚动到

UITableView 是不是支持带有矩形(非圆形)部分的分组样式?