Seeking To RePosition/ReShape a Canvas in iOS

The documentation for positioning things on an iOS screen is hard to follow. It is clear that the Left, Top, Width, and Height of the DesktopCanvas realm are read only in iOS and it is necessary to connect to the layout somehow, apparently by giving names to individual constraints.

The iOSlayoutConstraint documentation shows a similar solution for a Button, but it is unclear if it can be applied to a canvas.

For my purposes, it is probably fine to create a new canvas every time I need a new shape/position, but I do not understand where the code to do so should go and what the steps should be.

Is anyone doing this?

The first thing you need to do is give your control constraints names that are unique for the view. You can see here that I’ve named my constraints with the name of the control then the property (IE: Canvas1Left, Canvas1Top).

From there, you can use the View.Constraint method to get the iOSLayoutConstraint instance and set its Offset property:

self.Constraint( "Canvas1Left" ).Offset = System.Random.InRange( 0, 100 )
self.Constraint( "Canvas1Top" ).Offset = System.Random.InRange( me.Top + me.Height, 100 )
self.Constraint( "Canvas1Width" ).Offset = System.Random.InRange( 20, 120 )
self.Constraint( "Canvas1Height" ).Offset = System.Random.InRange( 20, 120 )

Example (5.8 KB)

Note that only the Offset can be changed with Anthony’s example. If you want to change anything else in a constraint, you’ll have to use the more complicated process of replacing the entire constraint.

You can change the offsets for all four sides or the dimensions. Which is what they asked.

Edit: Looks like Art edited his post to add information after I’d replied.

1 Like

Thank you Anthony and Art. This all looks right. It is taking me some time to incorporate as I seek to maintain a large single source with infinity #If Target… conditionals. In that realm, am I right that methods that manipulate a canvas need to know what kind it is (desktop or mobile) at compile time and hence I need to maintain two copies of each?

You can use Object or Variant to store your *Canvas instances.

Private canvasInstance as Object
#If TargetDesktop Then
  DesktopCanvas(canvasInstance).Width = 100
#ElseIf TargetMobile Then
  MobileCanvas(canvasInstance).Width = 100
#EndIf

Or

#If TargetDesktop Then
  var canvasToChange as DesktopCanvas = DesktopCanvas(canvasInstance)
#ElseIf TargetMobile Then
  var canvasToChange as MobileCanvas = MobileCanvas(canvasInstance)
#EndIf
canvasToChange.Width = 100

I think @David_Cox did a talk on this at the recent Conference hosted by @Christian_Schmitz .

Looks like this is the video from the session:

1 Like

Thank you for the pointer to this amazing talk. David’s approach definitely seems to meet the need, but I think it is above my pay grade. Xojo can be awkward and wordy in places, but I count on it to keep everything right out in the open in my source.

He did, however, make two other points that relate to my project. He encourages the use of containers. No problem for me; I have a couple dozen. The issue is placing them. In desktop, I use a one-hot approach, pushing them all out of the window, then positioning one at a time at the bottom of my window as needed. It is not clear that iOS supports the positioning of containers. David suggests the graffiti suite page panel. Do you have any insights on this?

1 Like

It is one of my products. It operates the same as the Desktop PagePanel, but with animation and some extended functionality. What would you like to know?

1 Like

In the attached little program, I have placed a container across the bottom of the screen and another in the upper left. I have then added a canvas directly on the screen upper right and another in the upper left container.

Using Anthony’s very helpful code, I can get a button directly on the screen to influence the canvas on the screen. I can also get a button within the container to influence the canvas within the same container. What I cannot figure out how to do is to have a button in the lower container influence either of the canvases or the shape of the upper container itself. Nor am I able to move the upper container using a button in the lower container. Is it possible to do any of this?

ContainerTest 5.xojo_binary_project.zip (9.6 KB)

When using a container as you did in the lower container, the buttons don’t know which canvas / control to act on.
There are several solutions to this, some being bad, some complex and some easier.

In this updated project, I am using events to propagate a button press.
ContainerTest 5_jly.xojo_binary_project.zip (10.1 KB)

When it comes to UI on iOS, try to forget everything you used to do with Desktop apps. Implicit instances doesn’t exist.

Yikes! Thank you Jeremie for digging in. Before I descend into this labyrinth and forget the desktop world, maybe you could give me insight on a simpler (?) question.

I am only interested in landscape mode iPads. Other than the Pro models, which I do not care about, they seem to stay pretty close to 1024x768.

I simply want to keep a canvas (mine happens to be 1024x590) and a changing control container (1024x160) centered on any iPad screen, with the control container usually below the canvas, but occasionally above. Controls in the control container then influence what is shown in the canvas. Without going into the details of how to do it, is this even possible on iPad?

A follow-on question is, if the iPad screen is bigger than my combined 1024x750, can I influence the solid color of the surrounding pixels?

First of all you should really add iOSDesignExtensions in your project if you haven’t already.
That will allow you to change the background color of a screen.
Alternatively you could place a rectangle control on any side of the container and set it to a specific color.

Relying on a fixed canvas size isn’t really a good idea, nevertheless it is still possible.

iPads now come in many different sizes (mini, 9", 11"…)

What if Apple decides to release a square or 16:9 iPad in the future…
That’s why designing UI on iPad is done with layout constraints. It is more complicated than control locking but so much better when it comes to adapting the UI to different sizes.

2 Likes

I agree about layout constraints being more flexible. I’ve got a landscape iPad app with a canvas that uses those constraints to adjust the canvas size depending on the device size. I space labels evenly along the top and left edges of the canvas which will vary with the size of the device.

Interesting note: To space the labels I need to know the Width and Height of the canvas, but these are not valid in the screen Opening or Activated events. So I used a timer with a short delay and adjust the label spacing constraints when the timer completes.