มุมมองย่อย UITableViewCell จะหายไปเมื่อเลือกเซลล์


178

ฉันกำลังใช้มุมมองตารางตัวเลือกสีซึ่งผู้ใช้สามารถเลือกได้ระหว่างพูดสี 10 สี (ขึ้นอยู่กับผลิตภัณฑ์) ผู้ใช้ยังสามารถเลือกตัวเลือกอื่น ๆ (เช่นความจุของฮาร์ดไดรฟ์, ... )

ตัวเลือกสีทั้งหมดอยู่ในส่วน tableview ของตนเอง

ฉันต้องการแสดงสี่เหลี่ยมเล็ก ๆ ทางด้านซ้ายของ textLabel เพื่อแสดงสีจริง

ตอนนี้ฉันกำลังเพิ่ม UIView สแควร์อย่างง่ายให้สีพื้นหลังที่ถูกต้องกับมันดังนี้:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RMProductAttributesCellID];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:RMProductAttributesCellID] autorelease];
        cell.indentationWidth = 44 - 8;

        UIView *colorThumb = [[[UIView alloc] initWithFrame:CGRectMake(8, 8, 28, 28)] autorelease];
        colorThumb.tag = RMProductAttributesCellColorThumbTag;
        colorThumb.hidden = YES;
        [cell.contentView addSubview:colorThumb];
    }

    RMProductAttribute *attr = (RMProductAttribute *)[_product.attributes objectAtIndex:indexPath.section];
    RMProductAttributeValue *value = (RMProductAttributeValue *)[attr.values objectAtIndex:indexPath.row];
    cell.textLabel.text = value.name;
    cell.textLabel.backgroundColor = [UIColor clearColor];

    UIView *colorThumb = [cell viewWithTag:RMProductAttributesCellColorThumbTag];
    colorThumb.hidden = !attr.isColor;
    cell.indentationLevel = (attr.isColor ? 1 : 0);

    if (attr.isColor) {
        colorThumb.layer.cornerRadius = 6.0;
        colorThumb.backgroundColor = value.color;
    }

    [self updateCell:cell atIndexPath:indexPath];

    return cell;
}

สิ่งนี้แสดงผลได้ดีโดยไม่มีปัญหา

ปัญหาเดียวของฉันคือเมื่อฉันเลือกแถว "สี" ในระหว่างการเคลื่อนไหวของการเลือกจาง ๆ ไปหาสีน้ำเงิน UIView ที่กำหนดเองของฉัน (colorThumb) ถูกซ่อนอยู่ มันสามารถมองเห็นได้อีกครั้งหลังจากที่แอนิเมชันส่วนที่เลือก / deselection สิ้นสุดลง แต่สิ่งนี้สร้างสิ่งประดิษฐ์ที่น่าเกลียด

ฉันควรทำอย่างไรเพื่อแก้ไขสิ่งนี้ ฉันไม่แทรกมุมมองย่อยในตำแหน่งที่ถูกต้องหรือไม่

(ไม่มีอะไรพิเศษใน didSelectRowAtIndexPath ฉันเพิ่งเปลี่ยนอุปกรณ์เสริมของเซลล์เป็นช่องทำเครื่องหมายหรือไม่ทำอะไรเลยและยกเลิกการเลือก indexPath ปัจจุบัน)


upadteCell คืออะไรเกี่ยวกับ?
Idan

updateCell ปรับแต่งเล็กน้อยเช่นการตั้งเครื่องหมายถูกหรือไม่โดยการเลือกสีของตัวอักษรขึ้นอยู่กับความพร้อมใช้งาน ... แต่ไม่มีการเปลี่ยนแปลงจริงที่เกี่ยวข้องกับเซลล์ตัวเองหรือ colorThumb
Cyrille

คำตอบที่ได้รับการยอมรับไม่ได้ให้วิธีแก้ปัญหาดูคำตอบของฉันด้านล่างเพื่อแก้ปัญหา
Pavel Gurov

คำตอบ:


227

UITableViewCellเปลี่ยนสีพื้นหลังของมุมมองย่อยทั้งหมดเมื่อเลือกเซลล์หรือไฮไลต์คุณสามารถแก้ไขปัญหานี้ได้โดยการแทนที่เซลล์ Tableview setSelected:animatedและsetHighlighted:animatedและรีเซ็ตสีพื้นหลังของมุมมอง

ในวัตถุประสงค์ C:

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
   UIColor *color = self.yourView.backgroundColor;        
   [super setSelected:selected animated:animated];

    if (selected){
        self.yourView.backgroundColor = color;
    }
}

-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated{
    UIColor *color = self.yourView.backgroundColor;        
    [super setHighlighted:highlighted animated:animated];

    if (highlighted){
        self.yourView.backgroundColor = color;
    }
}

ใน Swift 3.1:

override func setSelected(_ selected: Bool, animated: Bool) {
    let color = yourView.backgroundColor         
    super.setSelected(selected, animated: animated)

    if selected {
        yourView.backgroundColor = color
    }
}

override func setHighlighted(_ highlighted: Bool, animated: Bool) {
    let color = yourView.backgroundColor
    super.setHighlighted(highlighted, animated: animated)

    if highlighted {
        yourView.backgroundColor = color
    }
}

เราต้องการif (highlighted)และif (selected)เงื่อนไขหรือไม่? ฉันคิดว่ามันจะใช้งานได้ถ้าเราไม่มีเงื่อนไขเหล่านั้น
Rishabh Tayal

@RishabhTayal มันเป็นพื้นเพื่อหลีกเลี่ยงการเอาชนะตัวแปรที่มีมูลค่าเท่ากัน
cameloper

1
โปรดทราบว่าเมื่อคุณเปลี่ยนสีพื้นหลังในขณะที่เลือกรายการสี (ไม่ถูกต้อง) อาจถูกเรียกคืนเมื่อรายการไม่ได้ถูกเลือก หากสามารถเกิดขึ้นได้ให้ลบเงื่อนไข if (เน้น) และ (เลือก) เงื่อนไข
Marcel W

วิธีการนี้จะยกเลิกภาพเคลื่อนไหวดังนั้นจึงไม่มีเหตุผล ดีกว่าที่จะตั้งค่ารูปแบบการเลือกเซลล์เป็น. ไม่มี
Alexander Danilov

122

เป็นเพราะเซลล์มุมมองตารางเปลี่ยนสีพื้นหลังของมุมมองทั้งหมดภายในมุมมองเนื้อหาสำหรับสถานะที่ถูกเน้นโดยอัตโนมัติ คุณอาจพิจารณา subclassing UIViewเพื่อวาดสีของคุณหรือใช้UIImageViewกับภาพขยายขนาด 1x1 px ที่กำหนดเอง


1
ทำให้ฉันเป็นใบ้ แน่นอนว่าเป็นเรื่องรองต้องมีความโปร่งใสเพื่อให้ภาพเคลื่อนไหวการเลือกสามารถเกิดขึ้นได้อย่างถูกต้อง ขอบคุณ!
Cyrille

52
หรือคุณสามารถตั้งค่าสีพื้นหลังที่จะมาแทนที่setHighlighted:animated:และsetSelected:animated:
pt2ph8

1
การรีเซ็ตสีพื้นหลังไม่ได้ผลสำหรับฉัน (ใช้งานบน iOS 8.1) แทนที่จะแก้ปัญหานี้โดยการ subclassing มุมมองของฉันและแทนที่ setBackgroundColor เป็น [super setBackgroundColor: [UIColor whiteColor]]
bizz84

44

พบวิธีแก้ปัญหาที่สวยหรูแทนที่จะยุ่งกับ tableViewCell การเลือก / วิธีการเน้น คุณสามารถสร้างคลาสย่อยของ UIView ที่ละเว้นการตั้งค่าสีพื้นหลังเป็นสีที่ชัดเจน

สวิฟท์ 3/4:

class NeverClearView: UIView {
    override var backgroundColor: UIColor? {
        didSet {
            if backgroundColor != nil && backgroundColor!.cgColor.alpha == 0 {
                backgroundColor = oldValue
            }
        }
    }
}

สวิฟท์ 2:

class NeverClearView: UIView {
    override var backgroundColor: UIColor? {
        didSet {
            if CGColorGetAlpha(backgroundColor!.CGColor) != 0 {
                backgroundColor = oldValue
            }
        }
    }
}

รุ่น Obj-C:

@interface NeverClearView : UIView

@end

@implementation NeverClearView

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    if (CGColorGetAlpha(backgroundColor.CGColor) != 0) {
        [super setBackgroundColor:backgroundColor];
    }
}

@end

นี่มันช่างน่ารัก ทางออกที่ดีที่สุดได้อย่างง่ายดายหากคุณมีมุมมองที่สามารถนำกลับมาใช้ใหม่ได้เช่น "ตราสัญลักษณ์" หรือ "แท็ก" ที่ไม่ควรมีพื้นหลังชัดเจน :: พูดจาโผงผาง :: วิธีแก้ปัญหาที่น่าสับสน @UIKIT ตั้งค่ามุมมองของเด็กทั้งหมดให้โปร่งใสเมื่อคุณทำการเลือกเซลล์ อย่างน้อยก็ จำกัด จำนวนการดูเด็กที่มีความสูงเต็มหรือความกว้างของเซลล์หรือที่ความลึก N
SimplGy

@SimplGy ความลึกของการเน้นจะเป็นตัวเลือกที่แท้จริงหวาน แต่เดี๋ยวก่อน - นี้เป็น UIKit ผมได้เห็นสิ่งที่มากยิ่งกว่านี้ =)
พาเวลกูรอฟ

3
ทำงานให้ฉันหลังจากที่ฉันเปลี่ยน if เป็น CGColorGetAlpha (backgroundColor! .CGColor) == 0 เพราะมันไม่เท่ากับ clearColor
piltdownman7

9

อีกวิธีในการจัดการปัญหาคือเติมมุมมองด้วยการไล่ระดับสีกราฟิกหลักเช่น:

CAGradientLayer* gr = [CAGradientLayer layer];
gr.frame = mySubview.frame;
gr.colors = [NSArray arrayWithObjects:
                     (id)[[UIColor colorWithRed:0 green:0 blue:0 alpha:.5] CGColor]
                     ,(id)[[UIColor colorWithRed:0 green:0 blue:0 alpha:.5] CGColor]
                     , nil];

gr.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0],[NSNumber numberWithFloat:1],nil];

[mySubview.layer insertSublayer:gr atIndex:0];

อืมฉันกำลังลองใช้รหัสที่แน่นอนนี้และมันไม่มีผลกระทบใด ๆ เลยสำหรับฉัน มุมมองย่อยของฉันคือ UILabel เพิ่มเป็นมุมมองย่อยของ cell.contentView และการทดสอบภายใต้ iOS 6.0.1 ในกรณีที่มีความสำคัญ
Joe Strout

คุณใช้รหัสด้านบนเพื่ออะไร และคุณพยายามเพิ่มป้ายกำกับไว้ในมุมมองเซลล์หรือไม่
Agat

นี่เป็นทางออกที่สมบูรณ์แบบในความคิดของฉัน การวาดไปที่เลเยอร์แก้ปัญหาได้อย่างสมบูรณ์ในขณะที่ยังคงความยืดหยุ่นอย่างเต็มที่ ฉันไม่ชอบวิธีแก้ปัญหาของการใช้ UIImageView เพราะมันยากที่จะปรับการไล่ระดับสีหรือสี (คุณต้องสร้างภาพใหม่ทุกครั้ง) และ subclassing UIView เพียงแค่นี้ดูเหมือนจะเกินความจริง
Erik van der Neut

@Lyida ฉันไม่ใช่ Swift-Developer จริงๆ (ฉัน C # -one มากยิ่งขึ้น) แต่จากสิ่งที่ฉันเห็นนั่นไม่ใช่สิ่งเฉพาะภาษา แต่ส่วนใหญ่เป็นตรรกะของ Cocoa / iOS Frameworks ดังนั้นแนวคิดก็คือการวาง CAGradientLayer ที่โปร่งใสเกือบไว้ในมุมมองของคุณเพื่อรับผลลัพธ์ที่ร้องขอ
Agat

9

สำหรับSwift 2.2นี่ใช้งานได้

cell.selectionStyle = UITableViewCellSelectionStyle.None

และเหตุผลถูกอธิบายโดย @ Andriy

เป็นเพราะเซลล์มุมมองตารางเปลี่ยนสีพื้นหลังของมุมมองทั้งหมดภายในมุมมองเนื้อหาสำหรับสถานะที่ถูกเน้นโดยอัตโนมัติ


8

แรงบันดาลใจจาก คำตอบของ Yatheesha BL ฉันสร้าง UITableViewCell หมวดหมู่ / ส่วนขยายที่ช่วยให้คุณสามารถเปิดและปิดคุณสมบัติ "ความโปร่งใส" นี้ได้

รวดเร็ว

let cell = <Initialize Cell>
cell.keepSubviewBackground = true  // Turn  transparency "feature" off
cell.keepSubviewBackground = false // Leave transparency "feature" on

Objective-C

UITableViewCell* cell = <Initialize Cell>
cell.keepSubviewBackground = YES;  // Turn  transparency "feature" off
cell.keepSubviewBackground = NO;   // Leave transparency "feature" on

KeepBackgroundCell เข้ากันได้กับ CocoaPods คุณสามารถค้นหาได้ใน GitHub


7

คุณสามารถcell.selectionStyle = UITableViewCellSelectionStyleNone;จากนั้นตั้งค่า backgroundColor ที่- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath


4

แรงบันดาลใจจากคำตอบของYatheesha BL

ถ้าคุณเรียก super.setSelected (เลือกภาพเคลื่อนไหว: ภาพเคลื่อนไหว) มันจะล้างชุดสีพื้นหลังคุณ ดังนั้นเราจะไม่เรียกเมธอดซูเปอร์

ในสวิฟต์:

override func setSelected(selected: Bool, animated: Bool) {    
    if(selected)  {
        contentView.backgroundColor = UIColor.red 
    } else {
        contentView.backgroundColor = UIColor.white
    }
}

override func setHighlighted(highlighted: Bool, animated: Bool) {
    if(highlighted) {
        contentView.backgroundColor = UIColor.red 
    } else {
        contentView.backgroundColor = UIColor.white
    }
}

1
ขอบคุณสำหรับการแก้ปัญหา +1 การเอาชนะตัวแปร ishiglighted และ sethighlighted เป็นสิ่งที่แตกต่างกัน คำตอบที่ถูกต้องคือการแทนที่วิธี
Numan Karaaslan

4

สำหรับกรณีพฤษภาคมนี่คือ Septs เพื่อหลีกเลี่ยงการรับสีเทาสำหรับรายการทั้งหมดในเซลล์ (ในกรณีที่คุณใช้เซลล์มุมมองตารางแบบกำหนดเอง):

  1. ตั้งค่า selectionStyle เป็น. no 👉 selectionStyle = .none

  2. แทนที่วิธีนี้

    func setHighlighted (_ เน้น: Bool, ภาพเคลื่อนไหว: Bool)

  3. โทรสุดเพื่อรับประโยชน์จากการตั้งค่าขั้นสูง

    super.setHighlighted (ไฮไลต์ภาพเคลื่อนไหว: เคลื่อนไหว)

  4. ทำสิ่งที่เคยเน้นตรรกะที่คุณต้องการ

    override func setHighlighted(_ highlighted: Bool, animated: Bool) {
          super.setHighlighted(highlighted, animated: animated)
          // Your Highlighting Logic goes here...
    }

3

UITableViewCell เปลี่ยน backgroundColor ของการชมย่อยทั้งหมดที่เลือกด้วยเหตุผลบางประการ

สิ่งนี้อาจช่วย:

DVColorLockView

ใช้บางอย่างเช่นนั้นเพื่อหยุด UITableView จากการเปลี่ยนสีมุมมองของคุณระหว่างการเลือก


1

วาดมุมมองแทนการตั้งค่าสีพื้นหลัง

import UIKit

class CustomView: UIView {

    var fillColor:UIColor!

    convenience init(fillColor:UIColor!) {
        self.init()
        self.fillColor = fillColor
    }

    override func drawRect(rect: CGRect) {
        if let fillColor = fillColor {
            let context = UIGraphicsGetCurrentContext()
            CGContextSetFillColorWithColor(context, fillColor.CGColor);
            CGContextFillRect (context, self.bounds);

        }
    }


}

1

ที่ง่ายที่สุดในการแก้ปัญหาโดยไม่ต้องข้อบกพร่องที่มีภาพเคลื่อนไหว (ในขณะที่ด้านบนคำตอบการจัดอันดับ) และไม่มี subclassing และการวาดภาพ - สีเส้นขอบชั้นชุดแทน BackgroundColor และกำหนดความกว้างชายแดนที่ใหญ่มาก

colorThumb.layer.cornerRadius = 6
colorThumb.layer.borderWidth = colorThumb.frame.width
colorThumb.layer.borderColor = value.color

0

ลองรหัสต่อไปนี้:

-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{     
[super setHighlighted:highlighted animated:animated];
//Set your View's Color here.
}

0

อย่าลืมลบล้างsetSelectedเช่นกันsetHighlighted

override func setHighlighted(highlighted: Bool, animated: Bool) {

    super.setHighlighted(highlighted, animated: animated)
    someView.backgroundColor = .myColour()
}

override func setSelected(selected: Bool, animated: Bool) {

    super.setSelected(selected, animated: animated)
    someView.backgroundColor = .myColour()
}

0

นี่คล้ายกับคำตอบของ Pavel Gurov แต่มีความยืดหยุ่นมากกว่าในการช่วยให้สีใดถาวร

class PermanentBackgroundColorView: UIView {
    var permanentBackgroundColor: UIColor? {
        didSet {
            backgroundColor = permanentBackgroundColor
        }
    }

    override var backgroundColor: UIColor? {
        didSet {
            if backgroundColor != permanentBackgroundColor {
                backgroundColor = permanentBackgroundColor
            }
        }
    }
}

0

ฉันต้องการคงพฤติกรรมการเลือกเริ่มต้นไว้ยกเว้นมุมมองย่อยหนึ่งเซลล์ที่ฉันต้องการเพิกเฉยต่อการเปลี่ยนสีพื้นหลังอัตโนมัติ แต่ฉันก็ต้องสามารถเปลี่ยนสีพื้นหลังได้ในเวลาอื่น

วิธีแก้ปัญหาที่ฉันพบคือ subclass UIViewดังนั้นจึงไม่สนใจการตั้งค่าสีพื้นหลังตามปกติและเพิ่มฟังก์ชั่นแยกต่างหากเพื่อหลีกเลี่ยงการป้องกัน

สวิฟต์ 4

class MyLockableColorView: UIView {
    func backgroundColorOverride(_ color: UIColor?) {
            super.backgroundColor = color
    }

    override var backgroundColor: UIColor? {
        set {
            return
        }
        get {
            return super.backgroundColor
        }
    }
}

-1

นี่คือโซลูชันของฉันใช้ contentView เพื่อแสดงรายการที่เลือกสีใช้งานได้อย่างสมบูรณ์

#import "BaseCell.h"

@interface BaseCell ()
@property (nonatomic, strong) UIColor *color_normal;
@property (nonatomic, assign) BOOL needShowSelection;
@end


@implementation BaseCell
@synthesize color_customSelection;
@synthesize color_normal;
@synthesize needShowSelection;

- (void)awakeFromNib
{
    [super awakeFromNib];
    [self setup];
}

- (void)setup
{
    //save normal contentView.backgroundColor
    self.color_normal = self.backgroundColor;
    if (self.color_normal == nil) {
        self.color_normal = [UIColor colorWithRGBHex:0xfafafa];
    }
    self.color_customSelection = [UIColor colorWithRGBHex:0xF1F1F1];
    self.accessoryView.backgroundColor = [UIColor clearColor];
    if (self.selectionStyle == UITableViewCellSelectionStyleNone) {
        needShowSelection = NO;
    }
    else {
        //cancel the default selection
        needShowSelection = YES;
        self.selectionStyle = UITableViewCellSelectionStyleNone;
    }
}

/*
 solution is here
 */
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    if (needShowSelection) {
        self.contentView.backgroundColor = self.backgroundColor = color_customSelection;
    }
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesCancelled:touches withEvent:event];
    if (needShowSelection) {
        self.contentView.backgroundColor = self.backgroundColor = color_normal;
    }
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];
    if (needShowSelection) {
        UIColor *color  = selected ? color_customSelection:color_normal;
        self.contentView.backgroundColor = self.backgroundColor = color;
    }
}

-1

วางรหัสนี้ในคลาสย่อยของ UITableViewCell

ไวยากรณ์ของ Swift 3

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    if(selected) {
        lockerSmall.backgroundColor = UIColor.init(red: 233/255, green: 106/255, blue: 49/255, alpha: 1.0)
    }
}


override func setHighlighted(_ highlighted: Bool, animated: Bool) {
    super.setHighlighted(highlighted, animated: animated)

    if(highlighted) {
        lockerSmall.backgroundColor = UIColor.init(red: 233/255, green: 106/255, blue: 49/255, alpha: 1.0)
    }
}

-1

การเพิ่มโซลูชันอื่นหากคุณใช้กระดานเรื่องราว สร้างคลาสย่อยUIViewที่ไม่อนุญาตให้backgroundColorตั้งค่าหลังจากตั้งค่าเริ่มต้นแล้ว

@interface ConstBackgroundColorView : UIView

@end

@implementation ConstBackgroundColorView

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    if (nil == self.backgroundColor) {
        [super setBackgroundColor:backgroundColor];
    }
}

@end

-1

หากวิธีแก้ปัญหาเบื้องหลังดังกล่าวข้างต้นไม่สามารถแก้ไขปัญหาของคุณปัญหาของคุณอาจอยู่ในdatasourceTableView ของคุณ

สำหรับฉันฉันกำลังสร้างอินสแตนซ์ของวัตถุ DataSource (เรียกว่าBoxDataSource) เพื่อจัดการวิธีมอบหมายและ dataSource tableView วิธีดังนี้:

//In cellForRowAtIndexPath, when setting up cell
let dataSource = BoxDataSource(delegate: self)
cell.tableView.dataSource = dataSource
return cell

นี่เป็นสาเหตุที่ทำให้ dataSource ถูกจัดสรรคืนเมื่อใดก็ตามที่มีการแตะเซลล์และทำให้เนื้อหาทั้งหมดหายไป เหตุผลก็คือ ARC deallocating / เก็บขยะธรรมชาติ

เพื่อแก้ไขปัญหานี้ฉันต้องเข้าไปในเซลล์ที่กำหนดเองเพิ่มตัวแปรแหล่งข้อมูล:

//CustomCell.swift
var dataSource: BoxDataSource?

จากนั้นคุณต้องตั้งค่า dataSource เป็น dataSource ของเซลล์ที่varคุณเพิ่งสร้างขึ้นใน cellForRow ดังนั้นนี่จะไม่ถูกยกเลิกการจัดสรรด้วย ARC

cell.statusDataSource = BoxAssigneeStatusDataSource(delegate: self)
cell.detailsTableView.dataSource = cell.statusDataSource
return cell

หวังว่าจะช่วย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.