tombenner / nui Goto Github PK
View Code? Open in Web Editor NEWStyle iOS apps with a stylesheet, similar to CSS
License: MIT License
Style iOS apps with a stylesheet, similar to CSS
License: MIT License
What is the appropriate way to add line and block comment on .nss files?, thanks.
What is the preferred workflow for previewing NUI stylesheets? Are people just editing the style sheet and then Build-and-Run in Xcode?
I have this css:
OuterPictureFrame {
background-color: #FFFFFF;
border-color: #000000;
border-width: @primaryBorderWidth;
corner-radius: 2;
box-shadow: 0 1 1 rgba(0,0,0,0.2);
}
InnerPictureFrame {
box-shadow: inset 0 0 3 rgba(0,0,0,0.75);
}
None of this works, apart from the bg color - these are normal UIViews. Reading the code in NUIViewRenderer, it appears that it only processes background-color and background-image.
Adding borders would be trivial but I am not sure how to do box shadow. Let alone box shadow with an inset... (that's supposed to be an inner shadow and so far I haven't even figured out how to do that in the GLLayer... )
The following methods are duplicated in each custom views category.
UIXXX+NUI.h
@Property (nonatomic, retain) NSString* nuiClass;
@Property (nonatomic, retain) NSNumber* nuiIsApplied;
UIXXX+NUI.m
But since all components (labels, switches, etc) are descendants of UIView, should there be only a single category on UIView and rather than redefining the methods we may only include the UIView+NUI.h file.
I have been trying to make this library work for an app running on iOS5.x and have been facing some weid object reference issues. Is this library backward compatible with the earlier versions of iOS down to 5.x? If it's not, do you have an idea of what needs to be done to enable this?
text-shadow-color doesn't work on UIButton. Because you must use setTitleShadowColor to set it, not set on titleLabel directly.
You could add:
// Set shadow color
if ([NUISettings hasProperty:@"text-shadow-color" withClass:className]) {
[button setTitleShadowColor:[NUISettings getColor:@"text-shadow-color" withClass:className] forState:UIControlStateNormal];
}
to NUIButtonRenderer.m. Maybe should have text-shadow-color-highlighted, too.
This was initiated by @jphalip in #66, and the relevant commit is here.
@jphalip, you might've already caught this, but NUI's automatic rendering is usually done by overriding didMoveToWindow
; if you happen to know of (or can find) a similar method that's called whenever a UIWindow is about to be shown we could just override that.
Otherwise, does anyone else know of a method that would be appropriate? I haven't worked with UIWindow directly, but could take a closer look at this if nothing comes to mind for anyone offhand.
Setting up a UIWindowDidBecomeVisibleNotification
might be another option for this.
The README says that you should put [NUIRenderer init]; in the application:didFinishLaunchingWithOptions method. If you do this on the HEAD then the app crashes with the error:
+[NUIRenderer<0x107e78> init]: cannot init a class object.
Presumably this call is no longer needed as if I remove it the app is themed anyway?
Are there plans for OSX support?
I'm building a TableView app. I have copied the .nss file from the demo. However, while everything else is ok, the background for labels and for the nav. bar title are white while the background is E3E3E3 (roughly). I think there needs to be a background-color property associated with these elements.
Also note you are starred on Cocoa Controls today.
Congrats. It's a tremendous resource.
I just created a screencast on NUI. You can add this in Wiki
http://www.youtube.com/watch?v=isWn0BBJZZo&lc=8qxbL9lW6asUk9zbFkNPpesyubw6eL4KEmOEdMvOEac
I see in the sources you may have considered swizzling the drawRect: to ensure styles are applied when views are loaded programmatically.
- (void)swizzleDrawRect:(Class)class
{
[self swizzle:class from:@selector(drawRect:) to:@selector(override_drawRect:)];
}
Is there a way to avoid calling the [NUIRenderer render...] for views where awakeFromNib does not get called? (e.g. UITableViewCell) or NavigationBar not instantiated from a StoryBoard
I'm not sure for naming and other details, but just adding code like that will add this option:
if ([NUISettings hasProperty:@"selection-indicator-image" withClass:class_name])
{
[bar setSelectionIndicatorImage:[NUISettings getImage:@"selection-indicator-image" withClass:class_name]];
}
Currently, NUI has one type of selector that has traits of both class and element type selectors. We should support both element type selectors (e.g. button
) and class selectors (e.g. .large-button
). Perhaps the nuiClass
property on UI elements could be replaced by a nuiElementType
property and we could add a nuiClasses
NSMutableArray that's empty by default (with convenience methods like addNUIClass:
). Thoughts?
This has already begun in a small sense with NUIGraphics
. The next big step might be to support a box model that supports properties like margin
, padding
, border-*
, box-shadow
, and use this for all UI elements. Setting up support for custom graphics allows for many other applications, too, of course.
If anyone has thoughts on what the most valuable features would be for this, feel free to chime in.
Hi, I noticed that when using NUI, a styled UINavigationBar will not reduce it's size on rotation (usually it goes from 44 in portrait to 32 in landscape)
It comes from the fact that NUI inserts a subview in the UINavigationBar but doesn't remove it when rotating so the new bar is displayed but the previous one overlaps the difference beetween portrait and landscape
I've just refactored my app to use the "categories" branch as the proliferation of NUIView subclasses was indeed getting out of control and I agree this is a much better approach.
Unfortunately, it now seems that views that get loaded programatically, i.e....
-(void)viewDidLoad {
[super viewDidLoad];
[[NUISwizzler new] swizzleAwakeFromNib: [PSFooterBarView class]];
PSFooterBarViewController *fbvc = [[PSFooterBarViewController alloc] initWithNibName:@"PSFooterBarViewController" bundle:nil];
[self.view addSubview: fbvc.view];
Are not getting styled. It seems to me this is because NUI works by hot-patching over awakeFromNib:, which apparently does not get called on views that are instantiated using initWithNibName.
When overriding editingRectForBounds: in UITextField, call proper implementation of editingRectForBounds: from superclass. This fixes incorrect layouts when using accessory views. The code that fixes this is simply:
- (CGRect)override_editingRectForBounds:(CGRect)bounds {
if ([self nuiShouldBeApplied] &&
[NUISettings hasProperty:@"padding" withClass:self.nuiClass]) {
UIEdgeInsets insets = [NUISettings getEdgeInsets:@"padding" withClass:self.nuiClass];
return CGRectMake(bounds.origin.x + insets.left,
bounds.origin.y + insets.top,
bounds.size.width - (insets.left + insets.right),
bounds.size.height - (insets.top + insets.bottom));
} else {
return [self override_editingRectForBounds:bounds];
}
}
CSS defines a pretty robust syntax for building responsive layouts with @media
queries.
It would be exceedingly cool to be able to use them in this context to target device families and orientations. Perhaps something could be implemented with Auto-Layout Constraints to this effect.
Anyway, just wanted to put this out there as a feature request. Really psyched about the direction and momentum of this project. Well done, @tombenner!
(By the way, this was totally @dominic's idea originally. That guy is way smart.)
The border of the back button created by +[NUIGraphics backButtonWithClass:]
looks fine in retina resolution:
But in non-retina display it's blurry on the top, right, and bottom edges (they should have a width of 1px like the left edges have):
I'm not sure where the blurriness is occurring; I've taken a few stabs in the dark by removing resizingMode:UIImageResizingModeStretch
, setting shape.contentsScale
and shape.rasterizationScale
to [[UIScreen mainScreen] scale]
, and adjusting shape.shouldRasterize
to no avail.
Any ideas of how to fix this?
Instead of simply passing image paths as arguments to [UIImage imageNamed:]
, as in response to
Button {
background-image: image.png;
}
Allow more explicit references to images at standard iOS file system locations, for example
Button {
background-image: url(bundle://image.png);
background-image-highlighted: url(caches://highlighted.png);
}
Bundle paths can be mapped directly to files using [NSBundle pathForResource:ofType:inDirectory:]
while system specified directories can map prefixes to NSSearchPathDirectory
enum items then mapped to files using [NSFileManager URLsForDirectory:inDomains:]
.
All these changes could be isolated to the [NUIConverter toImageFromImageName:]
method. Retain existing behaviour if path is not wrapped in url().
Would be nice if you can have a selected state of a button.
for example: 'background-image-selected' and 'font-color-selected'.
Hiya. I'm trying to add support for setting the onTintColor of a UISwitch to my new fork of this library with the property on-tint-color.
E.g.
Switch {
on-tint-color: @primaryBackgroundTintColor;
}
I've been copying the way the other elements are styled (e.g. adding UISwitch+NUI and NUISwitchRenderer classes) and using similar implementations.
However, I'm running into an infinite loop issue with the code in UISwitch+NUI.m. This is identical to the implementations for UIView+NUI and UIButton+NUI etc, apart from the UISwitch class test.
- (void)override_didMoveToWindow
{
if (!self.nuiIsApplied) {
// Styling shouldn't be applied to inherited classes
if ([self class] == [UISwitch class]) {
[self initNUI];
[self didMoveToWindowNUI];
}
self.nuiIsApplied = [NSNumber numberWithBool:YES];
}
[self override_didMoveToWindow];
}
What I find particularly odd is how this code doesn't cause infinite loops in your other classes? Surely if self.nuiIsApplied is true, the code will loop forever? I presume I'm missing something about the internals of Obj-C here.
I can commit + push to my branch so you can see the code if this is useful. NOTE: If I remove the [self override_didMoveToWindow] call, then actually it does work and the UISwitch is correctly themed.
Thanks!
In the new version of NUI which uses Categories I have noticed that the border of the Button is now gone and this has to be created manually by the user. Is this intended or it this a bug?
Font-Size style does not work unless I first set the Font-Name.
I'd love to have some resizable image support like apple supports it:
(UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets
reference:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIImage_Class/Reference/Reference.html
I'm not an css expert so I don't know how such thing would be best handled with css syntax.
suggestion 1:
for every image property there is a inset property:
background-image
background-image-inset
suggestion 2:
background-image: image(NUIViewBackground.png, 0,0,0,0):
suggestion 3:
more nifty. support 9patch for ios ;)
(https://github.com/andylanddev/Tortuga22-NinePatch)
Arrows, for example.
The new version which uses Categories is bit confusing!! The section about creating custom styles is no where to be found in documentation. How do you create a LargeButton? Does it inherit from NUIButton class? The complete documentation is missing???
It'd be great if images referenced in NSS files could be reloaded when the NSS file is auto-updated. This'd really help speed up theme design as you can tweak an image and immediately see the result.
Presumably we'd need to somehow clean out the UIImage cache. Also, the new versions of images would exist only in the project and not in the bundle so I assume [UIImage imageNamed] isn't going to work.
So this sounds a bit tricky, but I think it's probably possible so long as we activate a debug mode or something where the images are loaded from the project rather than the bundle.
What do you all think?
Because NUI uses custom graphics (e.g. gradients) that cannot be tested by checking elements' properties programmatically, one approach for this might be to add elements to a view, render that view to an image, and then compare that image with an authoritative image of how the view should be rendered.
If each property of each element was tested incrementally, though, we'd need to work out how to organize those across authoritative images, as having a different authoritative image for every combination in that Cartesian product (element x property) might not be realistic.
Other thoughts on how to approach this?
This is currently handled with property suffixes (e.g. font-color-highlighted
), but it should be done with pseudo-classes instead (e.g. Button:highlighted {font-color: black;}
). We'll probably want to complete #33 before setting this up.
If I have a default UIBarButtonItem
style in my .nss file and when I call [NUIAppearance init]
I can't override those values using another class defined as runtime attribute on the Storyboard.
I've noticed that both NUIBarButtonItemRenderer
and NUIAppearance
are using setTitleTextAttributes
but I could not find the reason why the NUIBarButtonItemRenderer
is not overring the default value.
Example:
UIBarButtonItem {
background-tint-color: @primaryBackgroundTintColor;
font-name: @secondaryFontNameBold;
font-color: @primaryFontColor;
text-shadow-color: clear;
font-size: 13;
}
MyMenuButton {
font-color: #ff0000;
text-shadow-color: clear;
font-size: 18;
background-tint-color: none;
}
How can I set the margins of the text inside the Button? text-offset does nothing right now!
It seems like the call to the getInstance factory method initializes a stylesheet recursively calling itself and requiring NUIStyle.nss to be in the resources even if it ends up not being used.
+ (void)initWithStylesheet:(NSString *)name
{
instance = [self getInstance];
NUIStyleParser *parser = [[NUIStyleParser alloc] init];
instance.settings = [parser getStylesFromFile:name];
}
+ (NUISettings*)getInstance
{
@synchronized(self) {
if(instance == nil) {
[[NUISwizzler new] swizzleAll];
instance = [NUISettings new];
[self initWithStylesheet:@"NUIStyle"];
}
}
return instance;
}
2012-12-23 13:31:44.583 LocoPix[3106:c07] +[NUIGraphics gradientLayerWithTop:bottom:frame:]: unrecognized selector sent to class 0x74f1c
2012-12-23 13:31:44.583 LocoPix[3106:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+ [NUIGraphics gradientLayerWithTop:bottom:frame:]: unrecognized selector sent to class 0x74f1c'
*** First throw call stack:
(0x22e9012 0x1c19e7e 0x23742ad 0x22d8bbc 0x22d894e 0x33d23 0x2e988 0x37518 0x37418 0x386de9 0x5b248a 0x5b2a83 0x5b2b54 0x21a899 0x21ab3d 0xc21e83 0x22a8376 0x22a7e06 0x228fa82 0x228ef44 0x228ee1b 0x22437e3 0x2243668 0x16b65c 0x259d 0x24c5 0x1)
libc++abi.dylib: terminate called throwing an exception
(lldb)
I created a custom style called NUIGreenButton as shown below:
@interface NUIGreenButton : NUIButton
@implementation NUIGreenButton
I dragged a UIButton on the Interface Builder and set its class to NUIGreenButton. I edited the NUIStyle.nss file as shown below:
GreenButton
{
background-color: #3ADF00;
font-color:#190707;
font-name:Verdena;
font-size:50;
corner-radius:6;
height:50;
}
But the height never changes, Even the font never changes.
Descendant selectors (e.g. TableCell Button
to select buttons within table cells) would be very useful. The implementation should be such that it doesn't have to be completely refactored to accomodate #59.
It might not be terribly difficult; an element's ancestors can easily be found by recursively calling [element superview]
.
This code:
[NUIRenderer renderButton:doneButton withClass:@"SmallButton"];
doesn't inherit the properties of Button, which I thought was the desired behavior.
I've tried different methods of naming the class using CSS conventions (i.e. Button.SmallButton, Button SmallButton, etc), and also using the class name itself NUISmallButton
, but to no avail.
Is there a way to do this, or does this method only work in Interface Builder?
Hi
I tried running the test app today but it crashes on missing category selector
2013-01-29 09:43:46.739 NUIDemo[6823:707] -[UIImage resizableImageWithCapInsets:resizingMode:]: unrecognized selector sent to instance 0x1aa690
2013-01-29 09:43:46.744 NUIDemo[6823:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIImage resizableImageWithCapInsets:resizingMode:]: unrecognized selector sent to instance 0x1aa690'
*** First throw call stack:
(0x3568388f 0x37a2a259 0x35686a9b 0x35685915 0x355e0650 0x252a5 0x22ae3 0x228a1 0x21f09 0x330efcab 0x330e97dd 0x330b7ac3 0x330b7567 0x330b6f3b 0x3727622b 0x35657523 0x356574c5 0x35656313 0x355d94a5 0x355d936d 0x330e886b 0x330e5cd5 0x21e91 0x21e00)
terminate called throwing an exception
Wouldn't it be a better idea to use categories on standard UIKit components, instead of subclassing them?
That way you wouldn't have to change each element's class in Interface Builder or code;
You'd use them as they were standard UIKit components.
This would let developers modify style rules and restyle the UI while the app is running, without needing to recompile to see the changes' effects.
One approach could be to register NUI-styled elements in an array as they are rendered, and then reload the .nss and re-render those elements when the developer sends a signal during runtime (e.g. something like a shake gesture (Ctrl-Cmd-Z in iOS Simulator), though that's a little hacky).
We would want to be able to disable this for production code, so it would probably also make sense to create two modes for NUI (debug/test, production), which could be useful in other contexts, too.
If anyone has thoughts about what event should cause the rules to be reapplied (e.g. iOS Simulator gaining focus, a shake gesture, watching for when the NSS file is saved, etc) and how to implement it, feel free to weigh in on that, too.
LESS simplifies making highlight and shadow colors based on a primary colour by having a function that can darken or lighten an existing color.
I think this'd be pretty cool as it'd save the designer having to darken a color in Photoshop and then type the new value in.
Here's an example of how this might look in the NSS file, based on the current demo.
@primaryBackgroundColor: #E6E6E6;
@primaryBackgroundTintColor: lighten(@primaryBackgroundColor, 30%);
@primaryBackgroundColorTop: lighten(@primaryBackgroundColor, 50%);
@primaryBackgroundColorTop: darken(@primaryBackgroundColor, 30%);
Note you should also be able to use these functions in any place where a color can be defined (background color, border color etc).
LESS also has saturate and desaturate functions that alert the colour saturation, which may also be useful. http://lesscss.org/#reference
This request is definitely a non-essential, nice-to-have feature!
This might not strictly speaking be a bug, I wanted to point out that text-align on UIButton does not work as expected. This is because it is not enough to set textAlignment on titleLabel, as the label itself is centered. contentHorizontalAlignment would have to be set to UIControlContentHorizontalAlignmentLeft/Right or UIControlContentHorizontalAlignmentFill to achieve the desired effect.
Thank you for this very useful library.
NUIStyleParser
currently uses a number of regexes, and this isn't ideal going forward, as we want to be able to support more complex style rules. It looks like all of the major lexical analyzer generators that support C use licenses that don't play well with the App Store, but I may be overlooking something. @mattt had suggested CoreParse, which looks promising.
Tom, is there any reason why the NUI renderer class don't use inheritance? If they did then it would allow for reuse of style properties. For instance bulking up support in NUIViewRenderer could then add support for many UI components if they derived NUIViewRenderer. I mean, why not allow label backgrounds to have gradients, rounded corners, shadows, ...?
Hi, i found a bug in NUI, when styling a UISearchBar that uses a UIScopeBar, it displays correctly when loading the view but when the user search something, the scope bar dissapears and so does the styling on the UISearchBar.
Here is a video to illustrate:
http://www.youtube.com/watch?v=No4p1J9_mDk
Thanks !
Hi
Just wanted to ask if there is some possibility that a style StyleA:StyleB:StyleC which I define in nss file will be respected on an element with nuiClass = StyleC? Right now i'm setting inheritance by applying nuiClass = StyleA:StyleB:StyleC but it would be great if i could just set niuClass = StyleC and the .nss defined style would inherit form StyleA:StyleB automatically (like it is in css).
Cheers
The condition at the top of NUIButtonRenderer:
if ([button.layer.sublayers count] == 3) {
[button.layer.sublayers[0] setOpacity:0.0f];
[button.layer.sublayers[1] setOpacity:0.0f];
}
breaks if a button has a subview added to it. This results in image/background/... randomly disappearing.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.