Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Usage for UI components library #79

Closed
zdnk opened this issue Aug 16, 2017 · 13 comments
Closed

Usage for UI components library #79

zdnk opened this issue Aug 16, 2017 · 13 comments

Comments

@zdnk
Copy link
Contributor

zdnk commented Aug 16, 2017

Hey,
I have a question regarding the usage of Render in UI framework for multiple apps. Is it possible to use stateless ComponentViews as usual UIViews without a need to call update?

For example: if you setup autolayout constraints and the layout is calculated and new frames set, can the ComponentView actually automatically update it-self?

I want to have a collection of UI components/views/bits available in a separate framework and work with them as usual UIViews without the developer knowing it is actually Render based component. Even if he is going to use them with Render himself.

@zdnk zdnk changed the title Use for UI library Usage for UI library Aug 16, 2017
@zdnk zdnk changed the title Usage for UI library Usage for UI components library Aug 16, 2017
@alexdrone
Copy link
Owner

Absolutely yes - Render is designed to be stack-agnostic. It can be used within other view that utilize autolayout and it can wrap views that uses autolayout.
Let me know if you have a hard time with it.

@zdnk
Copy link
Contributor Author

zdnk commented Aug 19, 2017

Yes, I encountered an issue with size. I have autolayout setup the size of the component view to 200x300, but when I use layout.width = size.width and same for height in the render method of the component view, it is actually the size of the superview and not the constrained one.

@alexdrone
Copy link
Owner

If you can provide a workable example I can try to fix it :)

@zdnk
Copy link
Contributor Author

zdnk commented Aug 19, 2017

Here it is, sir :)

import Foundation
import Render

public class TestComponentView: StatelessComponentView {
    
    override public func render() -> NodeType {
        let container = Node<UIView> { view, layout, size in
            layout.width = size.width
            layout.height = size.height
            layout.padding = 10
            
            view.backgroundColor = .red
        }
        
        container.add(child: Node<UIView>{ view, layout, size in
            layout.percent.width = 100%
            layout.percent.height = 100%
            
            view.backgroundColor = .blue
        })
        
        return container
    }
    
}
import UIKit

class DetailViewController: UIViewController {

    func configureView() {
        title = detailItem
    }

    override func loadView() {
        super.loadView()
        let test = TestComponentView()
        test.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(test)
        
        let cts = [
            test.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            test.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            test.widthAnchor.constraint(equalToConstant: 200),
            test.heightAnchor.constraint(equalToConstant: 250)
        ]
        
        view.addConstraints(cts)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        configureView()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    var detailItem: String? {
        didSet {
            // Update the view.
            configureView()
        }
    }

@zdnk
Copy link
Contributor Author

zdnk commented Aug 20, 2017

I think it will be hard to achieve with AutoLayout :/

@alexdrone
Copy link
Owner

I have added an example on how to use Render with autolayout managed view hierarchies.

` override func loadView() {
super.loadView()

let avatar = AutoLayoutNestedComponentExample()
view.addSubview(avatar)
avatar.translatesAutoresizingMaskIntoConstraints = false

// Render component's view implement 'intrinsicContentSize'.
// To constrain them to a specific size you have to set  use 'referenceSize' proprerty.
// N.B: You can do this also in 'viewDidLayoutSubviews' if the size of the component is not
// static (e.g. could depend on another view layed out with autolayout).
avatar.referenceSize = { _ in return CGSize(width: 50, height: 50)}
avatar.update()

let cts = [
  avatar.centerXAnchor.constraint(equalTo: view.centerXAnchor),
  avatar.centerYAnchor.constraint(equalTo: view.centerYAnchor),
]
view.addConstraints(cts)

}`

@alexdrone
Copy link
Owner

This is a solution but I'm working on something prettier!

@zdnk
Copy link
Contributor Author

zdnk commented Aug 20, 2017

I see. However this will not work when you don't have specific constraints for height and width. You can have something like left = superview.left + 10 and right = superview.right - 10 for "margin".
EDIT: I see, you can do it in viewDidLayoutSubviews.
However you would have to do this sort of for every ComponentView used in autolayout I suppose? It is getting kinda hard to maintain.

I am afraid that ComponentView is not usable for AutoLayout for now :(

Maybe there should be an option to render withing current bounds? And call this whenever layoutSubviews is called? Somehow this must be possible to achieve.

@alexdrone
Copy link
Owner

alexdrone commented Aug 20, 2017

Ok - I've introduced AutoLayoutComponentAnchorView and it should solve all of your problems.
What do you think?

let avatar = AutoLayoutComponentAnchorView(component: AutoLayoutNestedComponentExample())
    view.addSubview(avatar)

    let cts = [
      avatar.centerXAnchor.constraint(equalTo: view.centerXAnchor),
      avatar.centerYAnchor.constraint(equalTo: view.centerYAnchor),
      avatar.widthAnchor.constraint(equalToConstant: 50),
      avatar.heightAnchor.constraint(equalToConstant: 50),
    ]
    view.addConstraints(cts)
  }

@zdnk
Copy link
Contributor Author

zdnk commented Aug 20, 2017

I was thinking of the same solution. What I don't like about this is that it wraps it yet in another UIView, the hierarchy becomes more complex and memory inefficient.

@alexdrone
Copy link
Owner

alexdrone commented Aug 20, 2017

I know, on the other hand an opaque, non-visible parent view is not a big overhead.

@alexdrone
Copy link
Owner

I can optimizeAutoLayoutComponentAnchorView by adding the component rootview rather than the componentview itself - that would result in a simplified view hierarchy.

@zdnk
Copy link
Contributor Author

zdnk commented Aug 20, 2017

Maybe that would be worth the effort. However, still, I don't feel entirely cool about this.
Maybe introducing some sort of Bool flag on ComponentView that its frame is calculated by AutoLayout and somehow change the behavior based on this flag?

EDIT: actually the same issue would occur when you would use Node<SomeComponentView> instead of ComponentNode, or not?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants