FramerJS layer with dynamic height (importing layers from sketch) - framerjs

At a high level, we’re trying to understand the best way for Framer to render a layer with a dynamic height.
We’re importing our designs into Framer from Sketch. We’re building a simple question and answer page. Each page has 1 question and the user will work through 20 questions, one question page after another.
Here’s a rough version of the design:
The header, footer, and prompt are always the same height.
The question and answers section change based on the question and answers we want to render.
We see three possible solutions:
Create 20 different sketch templates/cards, each one representing a rendering of a different question (for example card1 would be listing question1 with answers1). When the first question is answered we render the next sketch card to show question2 with answers2. To be clear, I’m suggesting that each card contains everything: the header, question, prompt, answers, and footer.
Have 1 sketch template/card that is the full rendering of the header, question1, prompt, answers1, and footer. Have a bunch of mini template/card layers that are also imported into Framer. There would be a layer for each question and a layer for each set of answers. When Framer tries to load question 2, it would load the full rendering of question1 with answers1 (and header,footer,etc), and swap the layer containing question1 with question2, and swap the layer containing answers1 with answers2. There’s a problem, question2 is smaller than question1, so now there’s a large white-space between the questions and prompt layer. So, programmatically go through the layers in Framer and properly align them using align.
Have several small layers (header, question1, question2, …, question20, prompt, answer1,...,answer20, footer) and using Framer build the page by adding each layer one after another. Also write CSS to match the design pixel perfect.
Problems:
Our issue with #2 is there’s a lot of upfront work to reposition ‘all the layers’. As far as we can tell, Framer copies all the sketch layers and positions them based on their absolute position with x and y coordinates. Since all layers are positioned absolutely it would have to go through each layer and re-apply align depending on how they’re positioning in reference to eachother. This really seems cludgey and as far as we can tell there’s no helper function in Framer to help achieve this. Sure, we can write something that works through the parent tree and re-aligns siblings, but this feels way too error prone and not in the spirit of building prototypes with Framer.
Our issue with #3 is this just feels like building the website and this doesn’t feel like prototyping. There’s a lot of pixel pushing since we can’t directly import the pixel-perfect sketch design. We want to quickly update the prototype when designs change. We expect the design will change frequently because we’re running a lot of user tests and getting great feedback. This method would have me spend considerable amounts of time churning each time a design is changed to ‘redesign’ my prototype.
Thoughts? Are we missing something obvious?
Thanks for reading and thanks for your time.

I don't know how much chrome you have around the cards, and if you want to define the margin between the layers inside Sketch, but writing a function to align a list of layers with variable height on top of each other doesn't actually have to be that hard:
stackLayers = (layerList, startY = 0, spacing = 0) ->
currentY = startY
for layer in layerList
layer.y = currentY
currentY = layer.maxY + spacing
Full example here: http://share.framerjs.com/sztcm5e9l4li/
If you keep the names of your Sketch layers containing the cards the same, you can re-import from Sketch and the repositioning will keep working, even if the size changes.
Because the structural tree of groups in your Sketch file is contained inside Framer, you can place all the layers you want to stack on top of each other in one group and call stackLayers(sketch.nameOfGroup.children, 0, 10) to stack all children of 'nameOfGroup' on top of each other.

We ended up solving this with approach #2. In summary: swap the layer and reposition all the layers below, also go through all the parents and resize as necessary (for example if the new layer is smaller than the old layer we're swapping with we'd need to shrink the parent layers by the difference).
The general approach was:
Use TextLayer to create a new layer with the new question text
Measure the size difference between the original sketch question text layer and our new TextLayer
Resize the parent layers based on the difference calculated in #2
Remove the original sketch layer
Insert the new TextLayer in the same x and y coordinates as the original sketch layer
Code gist: https://gist.github.com/MrNickBreen/5c2bed427feb8c701d5b6b1fbea11cb4
Special thanks to Niels for the suggestion which helped me figure this out.

Related

How to create UIView with custom shape propely?

I have to create UIView with custom shape, such as triangular, half-rect, etc.
I used to crop special image to that form and set as a background of my view.
Although it is a popular solution, I am not sure whether it is the most efficient one in terms of sustainability.
On the other hand, I found useful way of solving this problem with CAShapeLayer()
Could you please provide pros and cons of both approaches?
CAShapeLayer all the way!
With little effort you can achieve the same result with less memory (RAM) and less maintenance time (if you want to make the triangle thicker for example, you'll need a new image however a small change in code and you have it!). Moreover your app size will be relatively smaller and you don't have to worry about the resolution like the images.
Hope this helps!

PaintCode, How to add a frame around a portion of a vector and have it dynamically resize?

I've imported a vector layer from a psd into paint code v1, I'm trying to create a background image and make it universal.
I can't seem to add a frame around the vector, to complicate matters, I only need a portion, the center, of the layer. (The design is based around a circle, it has lines drawn towards the center of the circle.)
I can’t seem to add a frame to dynamically resize the part I need.
I found this http://www.raywenderlich.com/36341/paintcode-tutorial-dynamic-buttons the part about frame ans groups doesn't help me....
When I add a click frame and drag it around the area I need, it's at the same level as the vector layer. I've also tried adding a group around both, but that doesn't seem to obey the frame size either.
I’ve looked through the tutorials and googled adding a frame, but I can’t seem to achieve what I need.
EDIT
A frame is supposed to be at the same level as the vectors you're working with.
All you do then is set the resize rules of your vectors. There is a little rectangle in the frame's parameters interface with straight arrows and springs that you can modify to fit your wishes.
I think I also remember a checkbox setting to resize only what's inside the frame.
Now I haven't used PaintCode for a while, but if this doesn't help you, there probably is a problem with your vector layer.
I don't know if this information helps.
But if you resizing doesn't work as you expected. Look carefully at the transformation box (the one with the springs attached). When you have put a frame around your object. The middle dot in this box should be blue instead of green. if t's green, you may have a problem with the originating point of your objects and then the resizing may not work as you expected.

Apply definitely CGAffineTransform* to a UIView

I'm having a problem with scale transformation I have to apply to UIViews on Swift (but it's the same in objective-c too)
I'm applying a CGAffineTransformMakeScale() to multiples views during a gestureRecognizer.
It's like a loop for a cards deck. I remove the one on top and the X others behind scale up and a new one is added in the back.
The first iteration works as expected. But when I try to swipe the new front one, all the cards reset to their initial frame size because i'm trying to apply a new transform, which seems to cancel the previous one and reset the view to its initial state.
How can I apply definitely/commit the first transform change to be able to apply a new one after that based on the UIView resulting new size ?
I tried a UIView.commitAnimations() but no change.
EDIT :
Here's a simple example to understand what I try to do :
Imagine I have an initial UIView of 100x100
I have a shrink factor of 0.95, which means next views behind will be 95x95, then 90.25, then 85.73, etc
If I remove the top one (100x100), I want to scale up the others, so the 95x95 will become 100x100, etc
This is done by applying the inverse of the shrink factor, here 1.052631...
First time I apply the inverse factor, all views are correctly resized.
My problem is, when I trigger again by a swipe on the new front UIView a new resize of all views (So, for example, the 90.25x90.25 which became 95x95 should now scale to 100x100).
At this moment, the same CGAffineTransformMakeScale() is apply to all views, which all instantly reset to their original frame size (so the now 95x95 reset to 90.25x90.25, and then begin to apply the transformation on this old size).
As suggested here or elsewhere, using UIView.commitAnimations() in the end of each transformation don't change anything, and using a CGAffineTransformConcat() is like powering over and over the scaling by himself and of course views become insanely big...
I hope I made myself more clear, that's not easy to explain, don't hesitate to ask if something is wrong here.
After a lot of reading and consulting colleagues who know better than me about iOS programmation, here's my conclusion :
Applying a CGAffineTransformMakeScale() only modify visually a view but not its properties, and since it's difficult (and costly) to modify afterward the bounds and/or frame of a view, I should avoid to try to make a transform, update bounds, make another transform, etc.
Applying the same CGAffineTransformMakeScale() only reset the effect and not apply to the previous one.
Applying a CGAffineTransformScale() with the same values on top of the previous CGAffineTransformMakeScale() (or with a CGAffineTransformConcat()) has some unpredictable effect and will be very difficult to calculate precisely the new values to apply each time to get the effect I want.
The best way I can go with this is only applying one CGAffineTransformMakeScale() that I will keep updating scales values all along the view's life.
It implies now for me to rework all my implementation logic in reverse, but that's the easiest way to do this right.
Thanks all for your tips.

Growing a visual tree with rectangles?

Given rectangle-shaped bars (say, of size 50x10), how would I grow-draw them to something that looks like a tree? A starting point is given where a semi-randomly bar is added, and then a new bar or two are added to every end of the old rotation, rotated by themselves, and with new bars added at their end, and so on to some point. I suppose it's a geometry question -- how do I find the correct bar ends to stick the new rotated bar too?
I'm using Lua, but any pseudocode would help, thanks!
Have a look at L-systems. They can be used to create plant-like structures. The Wikipedia article has many references to sites where you can toy with these.
Let's see if I understand well the core of your problem: you have a segment (bar) which you rotate around one of its sides by some angle and you want to know the position of the other end of the bar after that.
Isn't what you're looking for just the geometric definition of sine and cosine?
See below, sorry for my awful drawing skills :)
To make it "stick" just rotate around the right corner of the rectangle depending on the angle, like so:

Checking for overlapping images with a hole in an image

I have two image views. They are "puzzle pieces" I want to test if one fits inside the other. Not that the frames overlap. I guess its a CGRect thing... but seems like they test the outer boundaries. Any ideas would be appreciated? Thanks.
Just brainstorming here... Maybe this will get you thinking of something that will work for you. If the images do not overlap, then drawing image A on top of image B will result in the same image as drawing image B on top of image A. If they overlap, that will result in different images. You could do something like draw image A, then B. Create a checksum of the result, draw A again, and checksum that. If the checksums match, the puzzle piece fits.
If you have a 1-bit mask that represents each image, then ORing them together and XORing them together will have the same result if they don't overlap and different results if they do.
Do you know the correct order of pieces beforehand? May be it's better assign the tag to each UIImageView which will represent the image's index number. Then you just create a kind of mesh and check in which cell the piece was placed. If the cell number and UIImageView tag match - then this is the right place.
If you have only two images and one must fit to the specific area in another, you could store the frame of this hole and check if the piece is placed somewhere around the centre of this frame. It'll be more user-friendly because when you're checking pixels or bit masks you want the user be extremely precise. Or your comparison code should allow some shifts and will be very complicated.
But if you don't want to hardcode the hole frame you could calculate it dynamically (just find transparent areas in the image). Anyway, this solution will be more effective then checking bit match on the fly.

Resources