Calling deselectRowAtIndexPath on custom UITableViewCell is not a fluid transition - ios

This is the setup of the portion of the app that is having issues.
MyTableViewController is my custom UITableViewController class.
TableViewController1, 2, and 3, are all of type MyTableViewController. 1 and 2 are the viewcontrollers controlled by a tabbarcontroller, 3 is pushed into the stack after a cell is selected from 1.
BaseCell is my UITableViewCell subclass.
MyCell1, 2, and 3 are all of type BaseCell.
The cells are setup like this
BaseCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
UIView *myContentView = self.contentView;
self.gradientView = [[UIView alloc] initWithFrame:myContentView.frame];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.colors = [UIColor grayGradient];
[self.gradientView.layer insertSublayer:gradient atIndex:0];
self.gradientView.backgroundColor = [UIColor blueColor];
[myContentView addSubview:self.gradientView];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
if (selected) {
self.gradientView.layer.hidden = TRUE;
} else {
self.gradientView.layer.hidden = FALSE;
}
}
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
[super setHighlighted:highlighted animated:animated];
// Configure the view for the highlighted state
if (highlighted) {
self.gradientView.layer.hidden = TRUE;
} else {
self.gradientView.layer.hidden = FALSE;
}
}
-(UILabel *)newLabelWithColor:(UIColor *)incomingColor font:(UIFont *)incomingFont
{
UILabel *newLabel = [[UILabel alloc] initWithFrame:CGRectZero];
newLabel.backgroundColor = [UIColor clearColor];
newLabel.opaque = YES;
newLabel.textColor = incomingColor;
newLabel.highlightedTextColor = [UIColor whiteColor];
newLabel.font = incomingFont;
return newLabel;
}
Thus every cell that extends the BaseCell has the gradient background. The Cell1, 2, and 3 continue to add more objects to the contentView in a similar fashion. Each cell is customized for a different purpose all follow the same format.
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
UIView *myContentView = self.contentView;
self.someLabel = [self newLabelWithColor:[UIColor blueColor] font:[UIFont boldSystemFontOfSize:12]];
[myContentView addSubview:self.someLabel];
self.someView = [UIView] alloc] init];
[myContentView addSubview:self.someView];
}
return self;
}
- (void)layoutSubviews
{
//Layout any views necessary
}
- (void)setupCell
{
self.someLabel = #"Placeholder Text";
self.someView.backGroundColor = [UIColor redColor];
}
Imagine the label is just a title in the cell and the view is a small bar on the left hand side of the cell indicating a state(the actual code has logic to determine different colors/states).
The final bit of information is that MyTableViewController doesn't seem to want to do cell deselection on its own. I do not have clearSelectionOnViewWillAppear = NO anywhere (and the default state is YES), yet cells are staying selected when I return to one of TableViewController1, 2. Oddly, 3 does not share in this behavior, and I cannot figure out why. Thus I implemented
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}
and deselection works. If I put it in viewWillAppear, it doesn't work. So my first question is, does anyone know why this behavior is happening? The standard behavior of UITableViewController is to leave a cell highlighted and then deselect it on return so that a user is reminded of what they had selected, as can be seen in something like Contacts. I'm wondering if this issue my be leading to my next problem, which is the topic of the post.
The cells look awful when they are being deselected. The flow is going like this Return To TableView -> Cell is highlighted blue in selected state -> Cell returns to highlighted state (all text is white with gradient background and self.someView is still invisible) -> cell returns to normal state (text is normal color and self.someView reappears). The transition is not fluid at all and you can clearly see the cell moving through these states, where as in Contacts the cell smoothly transitions with the blue fading and the normal text color appearing.
There is a ton of info here, and I've actually learned a lot about what is going on by writing this post, but I'm still confused if it is a problem with the deselection or if it is a problem with the way I've set up the cells or if it is possibly an issue in my overrides of setSelected and setHighlighted. Thanks for any help, I really appreciate it considering the amount of content here.

Related

How to show only the checkmark selection without the selection of entire UITableViewCell in edit mode of UITableView?

I have a TableView with custom UITableViewCells. I have UILongPressGestureRecognizer enabled for my tableview cells. On long tap of gesture recognizers, I wanted to edit my tableview. Now in the edit mode of the tableview, all the cells that are selected are getting selected along with the accessory checkmark button. I want only the accessory checkmark button to be selected and not the entire cell. I tried multiple options like setting the selectionStyle property of the cell as UITableViewCellSelectionStyleNone . In this case i am not able to select the cells in edit mode.
-(void)addLongPressGestureRecognizerForCell:(UITableViewCell *)tableViewCell{
UILongPressGestureRecognizer *lLongPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressGestureFunction:)];
lLongPressGesture.minimumPressDuration = 0.3;
lLongPressGesture.delegate = self;
[tableViewCell addGestureRecognizer:lLongPressGesture];
[lLongPressGesture setCancelsTouchesInView:NO];
}
How to achieve this functionality?
A simpler solution—and one that doesn't require changing the background to gray—is to set the multipleSelectionBackgroundView of your UITableViewCell to a clear box.
In Swift:
override func awakeFromNib()
{
super.awakeFromNib()
// Hide selection box in multi-select mode.
multipleSelectionBackgroundView = UIView()
multipleSelectionBackgroundView?.backgroundColor = UIColor.clearColor()
}
In Objective-C:
- (void)awakeFromNib
{
[super awakeFromNib];
// Hide selection box in multi-select mode.
self.multipleSelectionBackgroundView = [[UIView alloc] init];
self.multipleSelectionBackgroundView.backgroundColor = [UIColor clearColor];
}
Finally Got the Answer!!!!
All I need was to override the setSelected method and change the selectedBackgroundView for my tableViewCell in my custom tableViewCell class.
First i have added the backgroundview for my tableViewCell in cellForRowAtIndexPath method.
lCell.selectedBackgroundView = [[UIView alloc] init];
Next i have overridden the setSelected method as mentioned below.
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
UIImageView *lBalloonView = [self viewWithTag:102];
[lBalloonView setBackgroundColor:[[UIColor hs_globalTint] colorWithAlphaComponent:0.2]];
UITextView *lMessageTextView = [self viewWithTag:103];
lMessageTextView.backgroundColor = [UIColor clearColor];
UILabel *lTimeLabel = [self viewWithTag:104];
lTimeLabel.backgroundColor = [UIColor clearColor];
}
Also one of the most important point to be noted is to change the tableViewCell selection style.
lTableViewCell.selectionStyle = UITableViewCellSelectionStyleGray;

UITableViewCell reorder clears subview's background color

This question has been asked few times but there don't seem to be any solution to this.
UITableView reorder hides background
Subviews of UITableViewCell are not visible while reordering
Reordering causing subview 's backround color to clear
I have a custom tableview cell with UILabel in it. When tableview is in edit mode and I drag the cell to reorder, UILabel's background becomes clear color. I've also found that, if I try to reorder selected cell (my tableview is allowed multiple selection during edit mode), the subview's background color stays.
I tried below methods in my CustomCell but none of them overrides the subview's background color when cell is being dragged.
I want the subview's background color to stay. Is there any method that I missed? Or Apple designed it this way?
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if (selected) {
if (self.isEditing) {
self.customLabel.backgroundColor = [UIColor blueColor];
}
else {
self.customLabel.backgroundColor = [UIColor blueColor];
}
}
else {
self.customLabel.backgroundColor = [UIColor blueColor];
}
}
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
[super setHighlighted:highlighted animated:animated];
if (highlighted) {
if (self.isEditing) {
self.customLabel.backgroundColor = [UIColor blueColor];
}
else {
self.customLabel.backgroundColor = [UIColor blueColor];
}
}
else {
self.customLabel.backgroundColor = [UIColor blueColor];
}
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
if (editing) {
self.customLabel.backgroundColor = [UIColor blueColor];
}
else {
self.customLabel.backgroundColor = [UIColor blueColor];
}
}
Adding a modern solution for Swift 3.
Create a new .swift file and make a custom UIView class:
import UIKit
class NeverClearView: UIView {
override var backgroundColor: UIColor? {
didSet {
if backgroundColor?.cgColor.alpha == 0 {
backgroundColor = oldValue
}
}
}
}
In Interface Builder, go to the Identity Inspector and set the class to your shiny new NeverClearView class. This will halt it from disappearing during cell reordering.
This solution also works for other UIKit components, for example I had to do the same thing for a UIStepper a second ago.
You may create your custom UILabel. And overload -drawRect.
#interface VALAbel:UILabel
#property (nonatomic, strong) UIColor *bac_color;
#end
#implementation VALabel
-(void)setBac_color:(UIColor *)bac_color
{
_bac_color = bac_color;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
[self.bac_color set];
CGContextSetShouldAntialias(UIGraphicsGetCurrentContext(), true);
CGContextFillRect(UIGraphicsGetCurrentContext(), self.bounds);
[super drawRect:rect];
}
#end
This will help you!

UITableView cell selection

I've got a UILabel with a background color in a cell. When I select this cell, the cell changes the color (which it should) but it also changes the background of the label. I want the preserve the background color on the UILabel. When I use an image with just a random color in it it is preserved, but isn't there any better way?
Thanks in advance
Code:
_label = [UILabel new];
_label.translatesAutoresizingMaskIntoConstraints = NO;
_label.font = [UIFont systemFontOfSize:10.f];
_label.backgroundColor = HEXCOLOR(0xFFE5E5E5); //Macro just a UIColor
But I use this way to add a different selection color (could have something to do with it)
UIView *selectionColor = [[UIView alloc] init];
selectionColor.backgroundColor = HEXCOLOR(0XFFF1F1F1);
self.selectedBackgroundView = selectionColor;
self.contentView.backgroundColor = [UIColor whiteColor];
Nothing really more to it. Just a simple label added with autolayout to fill with a padding of 5.
Solution:
Create a subclass of UILabel and just not call super
- (instancetype) initWithColor:(UIColor *)color
{
self = [super init];
if (self) {
[super setBackgroundColor:color];
}
return self;
}
- (void) setBackgroundColor:(UIColor *)backgroundColor
{
//do nothing here!
}
The default behavior of UITableView is that when a cell is selected the background color of all the cell's subviews is temporarily removed.
We usually handled this issue by subclassing UILabel, overwrite setBackgroundColor: and simply do not call [super setBackgroundColor:] after we've set our own color.
#interface MyLabel : UILabel
#property(nonatomic) BOOL backgroundColorLocked;
#end
#implementation MyLabel
-(void) setBackgroundColor:(UIColor*)backgroundColor {
if (_backgroundColorLocked) {
return;
}
super.backgroundColor = backgroundColor;
}
#end
Usage:
MyLabel* label = …;
label.backgroundColor = UIColor.redColor;
label.backgroundColorLocked = YES;
As long as backgroundColorLocked is YES no-one, not even UITableView(Cell), can change the label's background color.

Views disappearing from UITableViewCell when selected

I have a UITableView with custom UITableViewCells. The content of the cell is kept in a separate class extending UIView (i have 3 kind of contents which i switch by hiding and showing views, i took this approach because of the way i wanted to make the transition between cells).
So let's assume i have one of the views visible and added to the contentView of the cell. This view contains some text and some rectangles made of UIViews. Everything good till now, but the weird thing is when i touch the cell, the rectangles simply disappears, the text stays the same. Do you know what might be the problem? I tried to add the view to the backgroundView as well, it's doing the same.
- (id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.active = NO;
state = -1;
// Touch is not working if the view has no bounds
self.backgroundView = [[UIView alloc] init];
self.backgroundColor = [UIColor clearColor];
self.selectedBackgroundView = [[UIView alloc] init];
self.selectedBackgroundView.backgroundColor = [UIColor clearColor];
self.clipsToBounds = YES;
self.contentView.clipsToBounds = YES;
// Add empty view
emptyView = [[View1 alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height) andRadius:CELL_DOT_RADIUS];
emptyView.userInteractionEnabled = NO;
[self.backgroundView addSubview:emptyView];
The view:
- (id) initWithFrame:(CGRect)frame andRadius:(int)r {
self = [super initWithFrame:frame]; radius = r;
if (self) {
int outerlineWeight = 1;
timelineView = [[UIView alloc] initWithFrame:CGRectMake(frame.size.width/4, frame.size.height/2, 1, 1)];
[self addSubview:timelineView];
dotView = [[UIView alloc] initWithFrame:CGRectMake(frame.size.width/4-radius, frame.size.height/2-radius, radius*2, radius*2)];
dotView.layer.cornerRadius = radius;
dotView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
[self addSubview:dotView];
UIView *n = [[UIView alloc] initWithFrame:CGRectMake(160, 0, 50, 20)];
n.backgroundColor = [UIColor redColor];
[self addSubview:n];
middleText = [[UILabel alloc] initWithFrame:dotView.frame];
middleText.font = [UIFont systemFontOfSize:12];
middleText.textColor = [UIColor grayColor];
middleText.backgroundColor = [UIColor clearColor];
middleText.textAlignment = NSTextAlignmentCenter;
[self addSubview:middleText];
This are the sources so you can try for yourself if you want. As you can see the orange rectangle disappears but the text not. For what i need to do nothing should disappear, in the best case i want to change their colours. http://ge.tt/6wRBObD1/v/0?c
You are adding it to background view. When selected the selected background view will display not background view. In your custom cell try
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
if (selected) {
[self.backgroundView addSubview:emptyView];
}
else{
[self.selectedBackgroundView addSubview:emptyView];
}
// Configure the view for the selected state
}
Or add empty view to contentview
one thing for frame settings u need to override "layoutsubviews" method ...
in custom cell
init all the views in initialisation method i,e ur - (id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier method and add it to cell
in - (void)layoutSubviews just set the frame for ur views in the cell,
use tag property to access the views in the layoutsubviews, if it is not the property
- (id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.active = NO;
state = -1;
// Touch is not working if the view has no bounds
self.backgroundView = [[UIView alloc] init];
self.backgroundColor = [UIColor clearColor];
self.selectedBackgroundView = [[UIView alloc] init];
self.selectedBackgroundView.backgroundColor = [UIColor clearColor];
self.clipsToBounds = YES;
self.contentView.clipsToBounds = YES;
// Add empty view
//emptyView = [[View1 alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height) andRadius:CELL_DOT_RADIUS];//dont set the frame heare do it layoutsubviews
emptyView = [[View1 alloc] init];
emptyView.userInteractionEnabled = NO;
emptyView.tag = 100;
[self.backgroundView addSubview:emptyView];
- (void)layoutSubviews
{
[super layoutSubviews];
UIView *emptyView = [self viewWithTag:100];//your background view heare u can get the frame values for ur cell
emptyView.frame = self.bounds;//better do it for other views in cell also
//test it by setting some background color
}
Hope this helps u ...:)
Ok, so like i've said in my last comment the backgroundColor of any subview is the problem, in the selected state is cleared. For cells created in interface builder the problem does not occurs, my cells are created programatically.
I fixed this by drawing with CoreGraphics in drawRect method.
As with a UICollectionView a UITableView has a background view that is build before AutoLayout. If you use autoLayout you should make sure the backgroundView has a frame. Otherwise is will disappear.
In your cell subclass you can do:
-(void)setBackgroundView:(UIView *)backgroundView
{
super.backgroundView = backgroundView;
self.backgroundView.translatesAutoresizingMaskIntoConstraints = NO;
[self.backgroundView autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsZero];
}
In swift you need to declare viewcontroller object globally that would result in Strong, in case if you declare locally it results in keep disappearing the cells.
var refineViewController : RefineViewController?
then you can access that controller using below code that would not result in disappearing cells.
func showRefineView(isFindHomeTab isFindHomeTab : Bool){
refineViewController = RefineViewController(nibName: String(BaseGroupedTableVC),bundle : nil)
refineViewController!.refineSearchDelegate = self
refineViewController!.view.frame = CGRectMake(0, -490, self.view.frame.size.width, self.view.frame.size.height)
UIView.animateWithDuration(0.3, delay: 0.0, options: .CurveEaseOut, animations:
{
self.refineViewController!.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)
self.refineViewController!.isFindHomeTab = isFindHomeTab
}, completion: nil)
self.view.addSubview(refineViewController!.view)
}

how to change TTStyledTextTableItemCell 's background

Suppose I create TTTableStyledTextItem objects in <TTTableViewDataSource> conforming class as follows:
NSString* text = [NSString stringWithFormat:#"<b>%#</b>\n%#", #"aaaa..", #"bbbb.."];
TTStyledText* styledText = [TTStyledText textFromXHTML:text lineBreaks:YES URLs:NO];
TTTableStyledTextItem* item = [TTTableStyledTextItem itemWithText:styledText URL:#"my://url"];
By default, the table view cell class returned by tableView:cellClassForObject: is going to be TTStyledTextTableItemCell.
This works all right by I'd like to customize the background color of the cell when it is in the normal state (when it is not in the selected state).
I've managed to change the cell's background in the selected state by creating a TTStyledTextTableItemCell subclass and overriding the initWithStyle:reuseIdentifier: initializer as follows:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString*)identifier {
self = [super initWithStyle:style reuseIdentifier:identifier];
if (self) {
// WORKS!
// cell's backgroundview (selected)
UIView *selectedView = [[UIView alloc] init];
selectedView.backgroundColor = [UIColor someColor..];
self.selectedBackgroundView = selectedView;
// DOESN'T WORK
// cell's background (normal)
UIView *normalView = [[UIView alloc] init];
normalView.backgroundColor = [UIColor someColor..];
self.backgroundView = normalView;
}
return self;
}
but I can't find a way to change the background of the cell when it's not selected (self.backgroundView). I know that there's an associated TTStyledTextLabel subview in the TTStyledTextTableItemCell class, but I still have no success customizing it.
Is there an easy way to achieve this??
Thanks

Resources