Git Product home page Git Product logo

Comments (37)

macfanatic avatar macfanatic commented on May 29, 2024

I've been an iOS dev since 4.0, so I might be a little stuck in my ways, but personally I'm fine with the way things are working currently. The only thing that would make me even happier would be if the add() method would also be defined on UIView so that I could do things like:

class WeatherView < UIView
  attr_accessor :conditions

  def self.new(conditions=nil)
    wv = alloc.initWithFrame([[0,0], [320,480]])
    wv.conditions = conditions
    wv
  end

  def initWithFrame(f)
    super
    add UILabel, font: :bold.uifont(12), backgroundColor: :clear.uicolor, placeholder: "Conditions"
    self
  end
end

This would also allow me to use add() more robustly in my controller, since I could call it on self and add to the self.view, but then I could also add items to existing views easily too:

class HomeScreen < PM::Screen
  def view_did_load
    @box = add UIView, frame: [[10,10],[40,40]], backgroundColor: :red.uicolor
    @box.add UILabel, font: :bold.uifont(12), backgroundColor: :clear.uicolor, placeholder: "Conditions"
  end
end

My rule of thumb is if I add more than 3-4 views in my controller, I need to create a view subclass & do my setup there. But it's so much easier to use the hash attributes syntax that add() provides :)

from promotion.

adelevie avatar adelevie commented on May 29, 2024

Pixate looks awesome and seems to be best equipped for out-of-the-box good design (e.g. with their Bootstrap port).

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

Let's move add into its own module and make it work with UIView subclasses, then. Work for you?

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

I agree, Alan. Pixate is definitely cool -- I was one of the Kickstarter supporters and have a T-shirt even. Haha...

from promotion.

Jasonbit avatar Jasonbit commented on May 29, 2024

Yah, Pixate is really cool. But I'm sure a lot of people don't want to pay for the license.

When I first checked out ProMotion this week (after working on many ios apps from first release of the sdk), I thought, yah, I like this approach of making things less obj-c (and I'm prob one of the few people who doesn't mind obj-c). Right now at my office we've fallen into the Storyboard trap - namely issues with merges all the time and not even sure you touched something which shows up as a regression in the build.

I've been thinking a lot about this problem for a few months and while we won't be switching our project over to Ruby Motion anytime soon, I still have a good sense of what I would like (in an ideal world). Maybe something between css and teacup..? (below doesn't really share much with css except in how properties could be considered for inclusion)

Stylescreen.new(:home) do

  # this could live in a base style class
  view do
    backgroundColor: "#edebe6".uicolor
  end

  # as could this
  button do
    titleFont: fontWithName('Signika-Regular', size:20),
    backgroundColor: "#edebe6".uicolor,
    borderWidth: 1.0,
    borderColor: "#e0ded9".uicolor,
    cornerRadius: 5.0
  end

  submit_button :extends => :button, :instance => true do
    left: 10,
    right: 10,
    bottom: constrain_above(:cancel_button)
  end

  cancel_button :extends => :button do
    left: 10,
    right: 10,
    bottom: constrain_pin(:bottom)
  end

end


class HomeScreen < PM::Screen
  # Not even sure this would be needed.. or maybe HomeScreen < PM::StyledScreen
  style :home

  def on_load

    # So we could hook up the events later
    @cancel_button = from_style(:cancel_button)
    @submit_button = from_style(:submit_button)

    add [@cancel_button, @submit_button]

    # or maybe by setting the :instance => true in the style you get a free @submit_button and 
    # you can avoid the above add to view code..? Just a thought. There's definitely reasons 
    # one might not want to do this, but this is ruby and i want to type less and get more :)

  end

end

Obviously this is closely related to teacup, but to me, this feels much more of what I would want with a Ruby library. It also gives me the added power of defining what I need in the context of ProMotion but not having to try to hack in teacup. I would love to ditch the CGRectMake calls in my implementation classes and have it work in the style definitions with autolayout. (Autolayout support is a must have in my mind.)

It's probably a decent amount of work with constraints, the implicit alloc/inits, and needing to decide what styles can be applied to the views/controls and layers. Probably less work than creating something like pixate tho..

Anyway, I just thought I'd chime in and it could be something I could set aside some time to contribute.

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

Thanks for the input, Jason! Good stuff.

One thing I want is to have a common handler for conversion of camel case to underscores. We can do that with a monkeypatch of String like the ActiveSupport's Inflector class:

class String
  def to_snakecase
    self.gsub(/::/, '/').
      gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
      gsub(/([a-z\d])([A-Z])/,'\1_\2').
      tr("-", "_").
      downcase
  end
  def to_camelcase(uppercase_first_letter=true)
    string = self.dup
    if uppercase_first_letter
      string = string.sub(/^[a-z\d]*/) { inflections.acronyms[$&] || $&.capitalize }
    else
      string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { $&.downcase }
    end
    string.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }.gsub('/', '::')
  end
end

This would allow us to handle ruby-style snake case and Obj-C's headless camel case for these attributes.

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

If you haven't caught on by now, nothing's really sacred with me as far as monkeypatching the crap out of RubyMotion. As long as it doesn't cause bugs or make a lot of gems incompatible I take a pretty pragmatic approach to this.

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

Just thinking out loud (figuratively) here...

ProMotion::Styles.define do
  style login_button: {
      title_font: fontWithName('Signika-Regular', size:20),
      background_color: "#edebe6".uicolor,
      border_width: 1.0,
      border_color: "#e0ded9".uicolor,
      corner_radius: 5.0
  }

  style profile_pic_view: {
    custom_style: something,
    layer: {
      something_inside_layer: 5
    }
  }
end

class HomeScreen < ProMotion::Screen
  def will_appear
    add UIButton, style: :login_button, on_touch: :log_in_action
    add CustomProfileView, style: :profile_pic_view, on_touch: :maximize_profile_action
  end

  # ...
end

Make add have all of the proper initializers mapped to as many UIKit objects as we can think of so you can just pass in the class and get a blank instance out of it.

Maybe the on_touch is going too far.

It might work better to make the style hashes into lambda blocks and not run them until called. I wouldn't want all that stuff sitting in memory.

from promotion.

Jasonbit avatar Jasonbit commented on May 29, 2024

Jamon,

I like that! Seems like a good direction to start with. I think you're right regarding the lambda blocks too. My one question would be what would make the most sense for breaking up the styles and then including them as needed. Not a hard problem to solve, but it would probable make sense from a maintenance perspective.

from promotion.

Swatto avatar Swatto commented on May 29, 2024

Jamon,

Your last proposition is very nice and I like the approch and the on_touch possibility. It could be great to have the possibilty to define the style inside the class of the view or the controller to avoid multiple class definition in addition to this (and be more readable).

And you with that kind of code, you could style an element and have a another element in an other view or controller with the same "style class" and be different.

class HomeScreen < ProMotion::Screen
  def will_appear
    add UIButton, style: :login_button, on_touch: :log_in_action
  end

  def styling
    style login_button: {
      title_font: fontWithName('Signika-Regular', size:20),
      background_color: "#edebe6".uicolor,
      border_width: 1.0,
      border_color: "#e0ded9".uicolor,
      corner_radius: 5.0
    }
  end
end

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

Good point, @Swatto ! That would actually work really well. Although, is that really much different than defining a method that returns the styles?

class HomeScreen < ProMotion::Screen
  def will_appear
    add UIButton, style: login_button_style, on_touch: :log_in_action
  end

  def login_button_style
    {
      title_font: fontWithName('Signika-Regular', size:20),
      background_color: "#edebe6".uicolor,
      border_width: 1.0,
      border_color: "#e0ded9".uicolor,
      corner_radius: 5.0
    }
  end
end

from promotion.

Swatto avatar Swatto commented on May 29, 2024

I think this approch is less powerfull than the styling method :

The def styling with all of the definition in it, have a major feature : we can generate style with event (a return name from a server, from an input of the user, etc).
With the name of the styling in a method definition name, we can't generate style by his name.

What do you think about it ?

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

You could do:

  method_name_here = :login_button_style
  add UIButton, style: send(method_name_here), on_touch: :log_in_action

send calls a method by a symbol or string name.

I do think this needs careful thought. We don't want to overcomplicate it.

The thing that I'm considering right now is lazy-loading the attributes hash. We don't want to hold all the attribute hashes in memory if they're not in use. A lambda or block would work but would be a bit awkward in all the scenarios I've imagined. Any thoughts?

from promotion.

Jasonbit avatar Jasonbit commented on May 29, 2024

I agree with Swatto, but not only for reasons listed, but also because of code separation and sharing.

Putting styles in a method of the (for instance) HomeScreen takes away all the power of this concept. Like css, a big part of the power of styles (for me anyway) is reuse and extensibility. I want one base button, for example, and then extend off that for multiple screens. And having this adhere to a file/naming convention, outside of implementation, would be really cool.

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

Agree, Jason. I'll do some thinking on this next week. Ideas welcome.

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

The thing that has me stuck on this one still is the memory usage. I don't want to store all the styles (and their associated objects) in memory in the chance that an element might use it. Even Teacup ends up instantiating a lot of styles without using them if you re-use stylesheets across ViewControllers.

It likely makes the most sense to create procs that only run when that style is called.

ProMotion::Styles.define do
  style :login_button do {
    background_color: UIColor.blackColor,
    font: fontWithName('Signika-Regular', size:20)
  } end

  style :logout_button, inherit: [ :login_button, :base_styles ] do {
    background_color: UIColor.redColor,
    font: fontWithName('Signika-Bold', size:20)
  } end

  # or maybe...

  style :logout_button do {
    include: [ :login_button, :base_styles ],
    background_color: UIColor.redColor,
    font: fontWithName('Signika-Bold', size:20)
  } end

end

The syntax looks slightly wonky, I realize, with the embedded hash, but this would be the most performant way to do this I believe -- a block (or proc) with a hash inside.

The inherit thing seems like it would work pretty well. You just merge the hashes. This would be fairly straightforward to implement.

from promotion.

markrickert avatar markrickert commented on May 29, 2024

Check out: https://github.com/tombenner/nui

And see an implementation i did here: https://github.com/Skookum/RubyMotionTalk/tree/master/RedditRss

I don't think element styling should be a part of ProMotion when there are so many other libraries that do it so well.

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

That looks really good. On your RedditRss app, I didn't see your stylesheet -- did I miss it somewhere?

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

I think I'll write an entire Styling section in the README and talk about Teacup, NUI, Pixate, and of course the built-in ProMotion system. I'm not sure how far I'll take the built-in system (it's fairly good already for in-place styling) -- the above is an idea and really depends on whether devs would like something like that or if they already have a favorite styling system.

I think a mixture of systems would work fine too -- we don't have to only support one. Teacup 2.0 (https://github.com/colinta/teacup/tree/2.0) looks like it will be pretty good and include support for Pixate and NUI. So it probably makes sense to just incrementally improve the internal system and recommend some of the other systems for more complex needs.

from promotion.

markrickert avatar markrickert commented on May 29, 2024

The stylesheet i'm using is the NUI default, therefore no need to declare it :)

One neat thing about NUI is that you can call setAutoUpdatePath with an absolute path for testing and as you save the stylesheet file, the interface in the simulator updates automatically! https://github.com/Skookum/RubyMotionTalk/blob/master/RedditRss/app/app_delegate.rb#L3

from promotion.

markrickert avatar markrickert commented on May 29, 2024

My only beef with NUI is that it's iOS 6 only... but when iOS 7 comes, out, I'll be dropping support for iOS 5.

iOS 5.1.1 is currently about 3% of my user base (roughly 10k people). Everyone else is on some versions of 6.

from promotion.

jasonlux avatar jasonlux commented on May 29, 2024

Yah, the NUI autoupdate is pretty cool, forgot abou that. :)

I have to admit tho, I do like Jamon's direction. Not that I couldn't do it in NUI or teacup, but this

  style :logout_button do {
    include: [ :login_button, :base_styles ],
    background_color: UIColor.redColor,
    font: fontWithName('Signika-Bold', size:20)
  } end

just looks very nice and clean to me. And that's the reason I gravitated towards ProMotion - I like the abstraction and the way things are represented. I dunno, the syntax just speaks to me more than the others.

@jamon, you're probably right about the instantiation - would be interesting to see what the memory usage might be for curiosity's sake.

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

I think if it doesn't take too much to implement (which I don't think it will) we might do this. Just gives users another option. But I'll make it clear that ProMotion can be used with your favorite styling system.

It'll be in a later release. Perhaps 1.0.

from promotion.

markrickert avatar markrickert commented on May 29, 2024

Damn. Promotion is going to eclipse bubblewrap in terms of functionality soon 😉

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

@markrickert Touché ...

I'm certainly willing to be talked out of this. I don't want to fall into the "not built here" syndrome. I agree with Jason that this syntax would make a lot of sense to me, though.

from promotion.

jamon avatar jamon commented on May 29, 2024

it seems as though you guys have accidentally added my account to this
thread ([email protected]).

On Wed, May 8, 2013 at 11:29 AM, Jamon Holmgren [email protected]:

@markrickert https://github.com/markrickert Touché ...

I'm certainly willing to be talked out of this. I don't want to fall into
the "not built here" syndrome. I agree with Jason that this syntax would
make a lot of sense to me, though.


Reply to this email directly or view it on GitHubhttps://github.com//issues/46#issuecomment-17617388
.

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

With a name as cool as that, @jamon, you should be involved. :) Sorry about that. Feel free to unwatch, of course.

from promotion.

jasonlux avatar jasonlux commented on May 29, 2024

Oh, whoops, sorry. I should have paid more attention.

@jamonholmgren I guess it's up to you, and sure, we don't want to fall into the not built here thing, but like I was saying earlier, the approach your taking feels best to me. So I guess that's my two cents.

from promotion.

jfi avatar jfi commented on May 29, 2024

I really like this, to throw my 2c in. Also a fan of the on_touch event.. :)

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

I'm currently working on a way to integrate the parts of Teacup that can help us here.

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

Looking at Teacup in more detail, I think it will work fine as-is. Since Screens are UIViewControllers, you can use Teacup normally.

I would recommend you use the instance method syntax (rather than the class method syntax):

class StyleScreen < PM::Screen
  title "Styles"
  stylesheet :standard

  def will_appear
    @view_setup ||= begin
      layout(self.view, :root) do
        # these subviews will be added to `self.view`
        subview(UIToolbar, :toolbar)
        subview(UIButton, :hi_button)
      end
      true
    end
  end

end

I'll write up a styling with Teacup guide at some point and include it in the repo.

from promotion.

Jasonbit avatar Jasonbit commented on May 29, 2024

So does this mean PM will only use Teacup for styling or will it have its own styling as well?

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

@Jasonbit: ProMotion will continue to have its own lightweight styling system with set_attributes and add. I'll continue to develop that as well and may even incorporate some of the ideas we had here. But after looking into what they've done with Teacup I think it's a fine choice for more demanding styling requirements.

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

ProMotion now supports Teacup styling in a very simple way. Just add stylesheet to your screen and stylename: to your add or set_attributes calls.

class HomeScreen < PM::Screen
  stylesheet :home

  def will_appear
    add UILabel.new, stylename: :teacup_style
  end
end

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

I decided to write a guide to styling views. It uses the simplest solution; one that doesn't eat memory nor require any modification to the current ProMotion styling code.

https://github.com/clearsightstudio/ProMotion/wiki/Guide%3A-Styling-Your-Views

Essentially, you define a module that gets mixed into your screen. To extend, it's relatively easy using parentstyle.merge({ new_styles: :whatever}). Just ruby, no magic. Then, you use that method in your add element call.

module MyStyles
  def button_style
    {
      background_color: UIColor.whiteColor
    }
  end
end

class MyScreen < PM::Screen
  include MyStyles

  def on_load
    add some_button, button_style
    add some_other_button, button_style.merge({
      some_override: :value
    })
  end
end

from promotion.

bartzon avatar bartzon commented on May 29, 2024

Has the add UILabel.new, stylename: :foo for Teacup option disappeared? :)

It doesn't work for me, and I can't locate it in the source files anywhere.

from promotion.

jamonholmgren avatar jamonholmgren commented on May 29, 2024

Addressed your question in the PR.

from promotion.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.