infinitered / redpotion

We believe iPhone development should be clean, scalable, and fast with a language that developers not only enjoy, but actively choose. With the advent of Ruby for iPhone development the RubyMotion community has combined and tested the most active and powerful gems into a single package called RedPotion
MIT License
234 stars 40 forks source link

title_view in PM::TableScreen doesn't work #121

Closed mixflame closed 7 years ago

mixflame commented 9 years ago

Hi!

I am trying to style a PM::TableScreen according to my client design specs.

The title_view command isn't working, I generated a new view using potion create view.

LineListScreen.rb

class LineListScreen < PM::TableScreen
  title_view Title.new
  refreshable
  searchable placeholder: "Search"
  stylesheet LineListScreenStylesheet
  include API

  def on_load
    @table_data = []
    load_async
  end

  def load_async
    get_lines do
      @lines = Line.all.to_a
      @table_data = [{
        cells: @lines.map do |line|
          {
            title: line.name,
            subtitle: "phone number"
          }
        end
      }]
      stop_refreshing
      update_table_data
    end
  end

  def on_refresh
    load_async
  end

  def table_data
    @table_data
  end

end

Title.rb

class Title < UIView

  def on_load
    apply_style :title

    append UILabel, :virtualq
  end

end

LineListScreenStylesheet.rb

class LineListScreenStylesheet < ApplicationStylesheet

  include TitleStylesheet

  def setup

  end

  def root_view(st)
    # st.superview.superview.frame = {l: 0, t: 0, w: 375, h: 648}
    # st.superview.superview.background_color = color.virtualq
    st.background_color = color.vq_gray
    # mp st
  end
end

TitleStylesheet.rb

module TitleStylesheet

  def title(st)
    st.frame = {l: 0, t: 0, w: 375, h: 64}
    st.background_color = color.virtualq
    # Style overall view here
    mp st 
  end

  def virtualq(st)
    st.frame = {l: 0, t: 0, w: 375, h: 64}
    st.text_alignment = :center
    st.text = "virtualQ"
    st.background_color = color.virtualq
    st.font = font.medium_small
    mp st
  end

end

As far as I can tell, Title.rb's on_load never gets called. The TitleStylesheet also never gets called.

Am I doing it wrong?

squidpunch commented 9 years ago

hi @jsilverMDX can you try to change your LineListScreen to be like this?

class LineListScreen < PM::TableScreen
  title_view build!(Title)
....

by doing this, you will use RMQ to build the view, which will call rmq_build which should enforce that on_load is fired. Otherwise, like you said, there really is nothing to tell a view to fire on_load (from what I recall...)

mixflame commented 9 years ago

thanks @squidpunch

I tried it and get the following

2015-06-11 13:06:13.603 virtualq-potion[91599:4134849] *** Terminating app due to uncaught exception 'NoMethodError', reason: 'undefined methodbuild!' for LineListScreen:Class (NoMethodError)`

squidpunch commented 9 years ago

interesting, its probably because this is a class level method so it doesnt know how to use build at that level (and might be troublesome because it might not know the stylesheet etc

but before that, how about this as a work around - does this work?

class LineListScreen < PM::TableScreen
title_view Title.new
...
  def on_load
    self.navigationItem.titleView.on_load
    # or you may you could even set the title view here with 
    # self.class.title_view build!(Title)
    ....
  end

I'd definitely consider this just a work around, and will see if we can make this work as we would expect instead of having to do it in this round about way...

twerth commented 9 years ago

Yeah, you always want to use append, create, or build to build views. If you don't, non of the stylesheet system will work. We should change title_view in PM::TableScreen to do that.

For now, just set your title view in the onload. I didn't look it up, but something like: title_view = create(Title, :title)

squidpunch commented 9 years ago

yeah I'd probably use the example @twerth gave for now until we can get this patched up.

I think you'd want to remove the title_view from the top, and add self.class.title_view create!(Title)

This should play nicely and fire the on_load for you.

jamonholmgren commented 9 years ago

title_view is a PM::Screen thing -- and yeah, we should detect if RMQ is present and use build!.

mixflame commented 9 years ago

Thanks guys.

# in on_load
title_view = create(Title, :title)
self.navigationItem.titleView = title_view.get

I was able to load Title view using this code.

But the result is not exactly perfect, there's an offet. I am not sure why.

http://cl.ly/image/41030v1d3O3e

Interestingly, when I tried using title_image, a similar sort of thing happened with the offset.

Am I doing something wrong in here?

module TitleStylesheet

  def title(st)
    st.frame = {l: 0, t: 0, w: 375, h: 64}
    st.background_color = color.virtualq
    # Style overall view here
    mp st 
  end

  def virtualq(st)
    st.frame = {l: 0, t: 0, w: 375, h: 64}
    st.text_alignment = :center
    st.text = "virtualQ"
    st.background_color = color.virtualq
    st.font = font.medium_small
    mp st
  end

end
twerth commented 9 years ago

Your cloudapp URL doesn't work

mixflame commented 9 years ago

Sorry about that.

http://cl.ly/image/41030v1d3O3e

squidpunch commented 9 years ago

@jsilverMDX if I can squeeze in sometime soon I will see if I can figure out what's going on here (sorry for the delay...)

mixflame commented 9 years ago

@squidpunch thanks! much appreciated :+1:

squidpunch commented 9 years ago

@jsilverMDX I was able to recreate this, but I wonder if it's actually a bug on any of the gems side..

Googling around a bit and it looks like this is just something like the UINavigationBar trying to position this view "properly" I think by default they don't think you want to go behind the status bar etc

I am guessing that you want to do a goldish background with the text in the center (that fills to the top including the status bar, etc)

I think you might want to try and handle this without a custom view (or at least one that doesnt do the background color) maybe with navigationBar.barTintColor or backgroundImageForBarMetrics to cover the background colors.

mixflame commented 9 years ago

that worked.

what I did exactly:

  def setup
    # setup navigation bar
    text_attrs = {NSFontAttributeName => font.medium_small, NSForegroundColorAttributeName => color.vq_black}
    self.controller.navigationItem.navigationBar.barTintColor = color.virtualq
    UINavigationBar.appearance.setTitleTextAttributes(text_attrs)
  end

in a stylesheet file. works well. it might be nicer to add some ruby abstraction for this though.

mixflame commented 9 years ago

Just out of curiosity, how would I "pull" the table view up a little bit? The design calls for some orange background... http://cl.ly/image/360w472m2n1H and I'm not really sure how to pull it up and dye that orange. I was able to pull stuff up with RMQ in sort of an ugly way... but could never figure out how to apply the color. Thanks for all the help so far! Right now, the list goes all the way down. http://cl.ly/image/3F2U3H1j342t But we're getting closer! :+1:

squidpunch commented 9 years ago

someone may have a different way to tackle this, but I think what I'd end up doing is the following.

1 - use a regular screen (instead of a table screen) 2 - append a UITableView to it that has a height of X units shorter than the screen 3 - append the footer view that is X units high, below the table

this keeps the footer at the bottom of the screen. Another option is tableFooterView but as that implies, its the footer of the table - so if you only have 1 item, the footer would not be at the bottom of the screen, and with many items the footer would be below the fold.

twerth commented 9 years ago

I'm not sure if it will work, but you can try contentInset.

jamonholmgren commented 9 years ago

I actually wouldn't mind adding another screen type, like PM::PartialTableScreen, that allows you to place the table as a subview anywhere but otherwise acts as a normal screen. Wouldn't be hard to do.

skellock commented 9 years ago

Heads up if you head that way.

iOS wants your table view to actually live in a UITableViewController because of focus control with your UITextFields and the keyboard.

UITableViewController is a silent workhorse. When your field gains first responder, the table scrolls to the right place to display.

It takes into account:

You can try your luck with UIScrollView’s scrollRectToVisible:animated: but that way lies madness.

I went there. I was sobbing in the fetal position for days.

mixflame commented 9 years ago

@jamonholmgren that does sound like it would work. I will try some of these suggestions later as well just for fun. The main thing that sells me with PM::TableScreen is the ability to easily drop in a lot of stuff I need like "searchable", "refreshable" really easily and all of the other syntactic sugar. @skellock that doesn't sound good. Probably better if we stick to the UITableViewController based screen for now. Especially because functionality is more important to us right now than design, thankfully. I would rather just use RMQ to "nip" the table up a little bit and just drop something orange behind it. If that would work.

squidpunch commented 9 years ago

@skellock makes valid points for sure, it totally depends on what your table is doing - I actually have used this pattern in my app quite a bit (a table view inside a UIViewController) etc.

@jamonholmgren I like that idea :+1:

but yeah there are definitely some things to consider depending on what you are doing with your table view.

skellock commented 9 years ago

Ya ignore what I said if you don't have NSResponder-based fields. Sorry to sound preachy or doom & gloomy.

Another potential option is you're inside a UINavigationController is adding your own custom toolbar subclass.

class DockingToolbar < UIToolbar

  attr_accessor :height

  def sizeThatFits(size)
    super_size = super
    super_size.height = @height || 100
    super_size
  end

end

And inject that sucker in:

navigation_controller.toolbar = DockingToolbar.new

Now at this point, it's important to remember your toolbar lives outside your screen, so as you push & pop, that thing is going to linger there.

Each screen can opt-out to this toolbar tho by hooking

def will_appear
  navigation_controller.setToolbarHidden true, animated: false
end

What's neat is here is: the transition animation of UINavigationController does the right thing. It actually looks like the toolbar is part of the screen.

Your table will lift up affording you the space you need.

In our app, our client uses this bottom area very frequently as if it were a fixed toolbar. I also swap UIButtons in & out of this area per-screen too.

But in your case, if you can find a better way and not have to write the above code, you should.

It took me 6 attempts to get that solution and I still feel like there still could be a better way.

Good luck champion!

squidpunch commented 9 years ago

definitely wasnt trying to steer you away from @skellock's tips. I might have to bug him more often for solutions on my own problems :)

jamonholmgren commented 9 years ago

Here's an API idea. Using RedPotion so I have RMQ available.

class MyScreen < PM::PartialTableScreen
  title "Normal title"
  stylesheet MyScreenStylesheet

  def table_data
    [{ cells: [{ title: "Normal table_data" }] }]
  end

  def on_load
    self.view # => UIView
    self.table_view # => UITableView
    find(:table_view) # => UITableView
  end
end

class MyScreenStylesheet < ApplicationStylesheet
  def table_view(st)
    st.frame = { top: 100, height: 200, centered: :horizontal }
  end
end
mixflame commented 9 years ago

@skellock, I tried it, and the code ran. but I wasn't able to add the toolbar to the screen. Don't know why.

@jamonholmgren it's not a bad idea, it gets the job done using a predictable api.

Ideally I'd like to just add maybe one more view under the table view, turn it orange, and just call code to change the frame of the TableView. is that possible? but I agree with Jamon that it is confusing to get a table view screen generated which is hard to style. if you guys need to take your time on this, that's fine, I can move on. it's not a blocker at all. thanks.

jamonholmgren commented 9 years ago

Good deal @jsilverMDX . Thanks for your input on this.

mixflame commented 9 years ago

@twerth just an update. I triedrmq(UIScrollView).get.contentInset = UIEdgeInsetsMake(0, 0, 19, 30) in console, and while it ran, nothing seemed to happen.

Edit: From all appearances, this is the 100% correct thing to do. However it looks like you have to do it before setting the view. As this is done automagically by Promotion, I'm stuck again. I will look into ways of correctly setting the contentInset. However that being said, a more customizable TableScreen sounds like ultimately the better solution to me.

andrewhavens commented 7 years ago

Closing due to inactivity.