ClassyKit / Classy

Expressive, flexible, and powerful stylesheets for UIView and friends.
http://classykit.github.io/Classy/
MIT License
740 stars 77 forks source link

Query the stylesheet from code #45

Closed wimhaanstra closed 10 years ago

wimhaanstra commented 10 years ago

I am using DTCoreText in my application and I would like to style the NSAttributedString ,that DTCoreText generates, using my stylesheet.

Currently I am using DTAttributedTextCell but all styling of text using DTCoreText is done by supplying a NSDictionary with a couple of parameters.

For example:

NSDictionary* options = @ {
    @"DTDefaultFontSize": @13,
    @"DTDefaultFontFamily": @"Helvetica Neue",
    @"DTDefaultTextColor" : [UIColor redColor]
};
[textCell setHTMLString:htmlText options:options];

My stylesheet:

DTAttributedTextCell.description {
    background-color: white;
    font: "HelveticaNeue-Medium" 13;
    text-color: black;
}

It would be a solution to query the Stylesheet in someway, that we get back a NSDictionary or something with the right values.

After that, the user should do the conversion themselves (Convert the UIFont to a Font Family text)

cloudkite commented 10 years ago

@depl0y How about subclassing DTAttributedTextCell instead then you can add the properties you need?

@interface MYAttributedTextCell : DTAttributedTextCell

@property (nonatomic, assign) CGFloat fontSize;
@property (nonatomic, strong) NSString *fontFamily;

@end

Then internally you could convert these values into the appropriate NSDictionary which DTCoreText recognises

Then you wouldn't need to query the stylesheet which would be fragile, since ideally views should not know about the stylesheets.

MYAttributedTextCell.description {
    font-size: 13;
    font-family: "HelveticaNeue-Medium";
}

One thing to bear in mind is that views are styled when a view moves into a window. So your new properties would be set once didMoveToWindow is called

so you might need something like

@implementation MYAttributedTextCell

- (void)setHTMLString:(NSString *)HTMLString {
    _HTMLstring = HTMLString;
    NSDictionary* options = @ {
        @"DTDefaultFontSize": @(self.fontSize),
        @"DTDefaultFontFamily": self.fontFamily,
         //...
    };
    [super setHTMLString:HTMLString options:options];
}

- (void)didMoveToWindow {
    [super didMoveToWindow];

    // make sure latest options are used
    [self setHTMLString:_HTMLString];
}

@end
wimhaanstra commented 10 years ago

Yes, this is working. I took a different route, I let Classy style the textLabel of the cell (it inherits from UITableViewCell), so I do not need other variables to store customization in.

But, there is another problem. The DTAttributedTextCell uses the following steps to determine the height of the cell:

  1. Initiate a cell
  2. Set the HTML string with the right options (font-size, font-family, etc)
  3. Some interesting calculations happen on the cell, to determine the height
  4. Cell is being cleaned up.
  5. Return the height

The problem of course, is that the cell is not moving to the window, so the right styling is not applied while calculating the height of the cell.

I have overridden the requiredRowHeightInTableView method in my subclass of DTAttributedTextCell, try to call the didMoveToWindow myself, but this is making sure I end up in an infinite loop.

- (CGFloat) requiredRowHeightInTableView:(UITableView*) tableView {
    [self didMoveToWindow];
    return [super requiredRowHeightInTableView:tableView];
}

https://github.com/Cocoanetics/DTCoreText/blob/develop/Core/Source/DTAttributedTextCell.m

Edit: In my own project (which I am moving to Classy) I have also adopted this method, maybe a better question would be: Is there a way to have classy 'populate' the properties with the right values in code?

But I understand I would then encounter the problem: As long as the control is not added to the right view yet, which part of the stylesheet should be applied, because we don't know that yet.

Hmmm, this seems to be a problem I am having with the way I populate my tables, because I use calculated heights at a lot of places..

wimhaanstra commented 10 years ago

Fixed! I made the styling for the object less specific:

DescriptionAttributedCell instead of ProductViewController > DescriptionAttributedCell

And after instantiating the cell, I call the didMoveToWindow method by hand on the object.