colinta / teacup

This project has been sunset in favor of MotionKit
github.com/motion-kit/motion-kit
Other
604 stars 85 forks source link

Adding a subview dynamically #146

Closed stefanvermaas closed 10 years ago

stefanvermaas commented 10 years ago

Hi,

Is it possible to dynamically generate a subview? So I click on an button, but want to show an error view if there should be an error, than an error view show popup.

This is what I've got, but it doesn't seem to work:

# index.rb
        @error_view = ErrorView.new
        self.addChildViewController @error_view
        subview( @error_view.view  )

# error_view.rb
class ErrorView < PM::Screen

  # - Styling code ------------------------------------------------------------ #
  stylesheet :alerts
  def on_load
    layout(self.view, :error_view) do
      subview(UILabel, :error_view_message, text: @message)
    end
  end

end

# error_view_style.rb
Teacup::Stylesheet.new :alerts do

  style :error_view,
    backgroundColor: '#f2dede'.uicolor,
    layer: {
      borderColor: '#ebccd1'.uicolor,
      borderWidth: 1,
      cornerRadius: 5
    },
    constraints: [
      constrain_size( 680, 50 ),
      constrain(:top).equals(:superview, :top).plus(10),
      constrain(:left).equals(:superview, :left).plus(30)
    ]

  style :error_view_message,
    color: '#b94a48'.uicolor,
    textAlignment: :center,
    constraints: [
      constrain_size( 660, 30 ),
      constrain(:top).equals(:error_view, :top).plus(10),
      constrain(:left).equals(:error_view, :left).plus(10)
    ]

end

But I receive this error:

teacup_view.rb:196:in `block in get_ns_constraints': Could not find :superview (RuntimeError)

Any idea? I'm also using ProMotion fyi.

Cheers.

jamonholmgren commented 10 years ago

I think you need to use will_appear rather than on_load. on_load fires too early.

  def will_appear
    @view_set_up ||= begin # so it doesn't fire more than once
      subview(self.view, :error_view) do
        subview(UILabel, :error_view_message, text: @message)
      end
      true
    end
  end
colinta commented 10 years ago

calling subview in this way will add the view to self.view (when called from a controller), the layout block doesn't make any difference. so yeah, @stefanvermaas your code looks correct; are you using something to output your view hierarchy? At the least, the ErrorView instance should be there, my guess is that the frame isn't set.

stefanvermaas commented 10 years ago

Hi @colinta seems you're right: screenshot, but I do set the constraints, so this is a kinda weird isn't it?

It seems the stylesheet isn't applied or so.. Though the :superview instance does crash the whole app, because:

Blossom[86880:80b] teacup_view.rb:196:in `block in get_ns_constraints': Could not find :superview (RuntimeError)

@jamonholmgren: Now the view does appear, but it replaces the current view.. Changing subview(self.view... to subview(UIView... did make the above error disappear, but the view still isn't on the screen.

colinta commented 10 years ago

Ahh, settings constraints dynamically is a bit trickier... you might need to call update_constraints on the superview

stefanvermaas commented 10 years ago

Thanks @colinta for your answer. I don't know where to call update_constraints. Though this didn't work, I found a solution to my problem. I had to define layout "the normal way", this where I end up working with:

class ErrorView < PM::Screen

  # - Styling code ------------------------------------------------------------ #
  stylesheet :alerts
  layout do
    subview(UIView, :error_view) do
      subview(UILabel, :error_view_message, text: @message)
    end
  end
  ...