The `layout` is `protected` to prevent arbitrary c...
# doodle
n
The
layout
is
protected
to prevent arbitrary code from changing it for a view that assumes it has a particular one. Same goes for the render. But it’s easy to make a new view with whatever you’d like for these. The first option is to use the view builder. This will let you specify the render behavior (but not layout, though this might make sense to expose there as well).
Copy code
val view = view {
    render = {
       // this points to a Canvas
       rect(…)
    }
}
The second is to override render or set layout in a derived class:
Copy code
object: View() {
    init {
      layout = …
    }

    override render(…) {…}
}
The
container
builder lets you set the
layout
by the way.
c
container is a view right??
n
it is. just one that exposes the fact that it has children (all views can keep this a secret) and a layout. you would use a container (or your own sub class that exposes these) if you’re ok with other code being able to modify these things for that view. this doc talks about why children are hidden by default as well, by showing that it makes a hypothetical split panel better encapsulated.
c
Yea i read that and it makes sense. I think its best to create a container if i want more power. Thanks
Do you have any idea why: the ui doesn't react to screen size? For example, when i close the inspector in the browser the part it covered when opened will be blank when close
n
this maps to the
Display
size. do you have a
layout
set on the
Display
? how do you position your views?
Display
size will change when to top-level window (or element if your app is embedded) changes like this. the `Display`’s
layout
(if it has one) will be called to reposition the top level views (just like a container’s layout would be called if it changes size). so you can set a layout on the Display to manage this automatically. Can you share how you position the views?
c
Copy code
constrain(views.first()){
            <http://it.top|it.top> eq 0
            it.left eq 0
Just a single view
Its a button with 50 height and width of Display.size.width
n
ok. so you need to constrain the view’s width/height. you can do that like this:
Copy code
it.width eq parent.width
it.height eq parent.height
or
Copy code
it.right eq parent.right
it.bottom eq parent.bottom
you could also use a
fill
like this
Copy code
display.layout = constrain(view, fill)
there’s also a version of fill that takes an
Insets
if you’d like some padding around the view.
c
If i constrain to parent bottom or height, i loose the button's height of 50
n
ok. then you can only constrain the width then. what’s the red portion? is that a container with the other blue views as children? looks like you have several views in your app.
c
Sorry, thats an example not the current UI that i am working on😅
But i understand you clearly
@Nick Hello. Is there a reason `parent`View is null??
n
yep. a
View
only has a non-
null
parent
if it has been added as a child to another
View
. they key here is that top-level views (those added directly to the
Display
) will have a
null
parent
. this is intentional. it avoids having
Display
share an interface with
View
. which avoids it being added into the view hierarchy. the docs explain this as well.
c
Okay. I understand
Copy code
val button = PushButton("Welcome").apply {
            size = Size(600.0, 40.0)
            println("Parent: ${parent?.size}")
        }
        val text = TextField().apply {
            size = Size(display.size.width, 40.0)
        }
        val container = container {
        children += button
        size = button.size
            layout = constrain(button){
                <http://it.top|it.top> eq 0
                it.left eq 0
                it.right eq parent.right
            }
        }
        display += container
        display.layout = constrain(display.children.first()){
            <http://it.top|it.top> eq 10
            it.left eq 10
            it.right eq parent.right - 10
            it.bottom eq parent.bottom - 10
        }
So the println in PushButton prints null. Is that supposed to be so?
n
that’s right, because the apply runs immediately before the button is added to container. you should see a non-null if you print the
parent
after adding it. also,
View
has a
parentChanged
event you can listen to if you wan my to.
c
@Nick I have toiled over this but couldn't get desired output. So i have 2 views in a constraint, i want them to react to width change. So i did:
Copy code
constraint(button,text){v1, v2 ->
<http://v1.top|v1.top> eq   0
                v1.left eq  0
                v1.height.preserve
                v1.right eq parent.right - v1.right

                <http://v2.top|v2.top> eq   v1.bottom
                v2.left eq  0
                v2.right eq parent.right - v2.right
                v2.height.preserve
}
Because i want the view to resize only if the parent width is less than it's width. It should maintain width if parent is bigger. But with my code above my view's width is always bigger than specified width
n
you'll need to use constraint strengths to get that this way you can have a constraint that is broken when the parent width is a certain value:
c
Thanks. Let me play around with it.
n
you could also use min instead of having two constraints by the way:
Copy code
constrain(view1, view2) { v1, v2 ->
    <http://v1.top|v1.top> eq 0
    v1.left eq 0
    v1.height.preserve
    v1.width eq min(parent.width, 50)

    <http://v2.top|v2.top> eq v1.bottom
    v2.left eq v1.left
    v2.height.preserve
    v2.width eq min(100, parent.width)
}
c
Yea, it works. After resize due to parent change, it should go back when the parent is big enough right?
n
yep
code?
c
Copy code
constrain(views.first()){
                <http://it.top|it.top> eq   0
                it.left eq  0
                it.width eq min(parent.width, it.width)
            }
n
so the value you pin on should be a "constant" or something other than the view's width, which will change as it resizes. so you can have an actual constant (like my example), or some other variable that defines the "default" width you want for that button.
c
Yea, it worked. Thanks.
Don't mind my bother. We are building a compose like api on Doodle in my company to help faster adoption at work. So really hope you don't mind, and you will support us when you can.
I want to write something like:
Copy code
v1.width + v2.width eq min(parent.right, 600)
n
what do you mean? is the list of views in the container unbounded? if so, you might want to use another type of Layout (here is HorizontalFlowLayout for example). Layouts can iterate over the container and position the views however they want. Or, you can use constraints like this.
c
Okay so what I want to implement is have a row effect where every widget is beside each other. Also i want all the view to react to size change, which I see you implemented here in the second example. In the example code you did:
p1.width + p2.width + p3.width eq parent.width - 2 * inset
i want implement that too but I won't know how many views will be in the constrain. So it'll be a list of bounds, how can I have same effect?
n
i see. you’d like the views to all stack horizontally and resize with their parent. you can do this with a custom
Layout
like this:
Copy code
layout = simpleLayout { container ->
    var x = 0.0
    val width = container.width / container.children.size
    container.children.forEach { view ->
        view.bounds = Rectangle(x, 0, width, container.height)
        x += width
    }
}
this just stacks the views horizontally with no padding and gives then same fraction of the parent’s width, while anchoring them at the top and bottom of it. not sure if that helps.