Following a Framer workshop example verbatim and for some reason cannot get a conditional statement to work.
This code runs as expected
layerA = new Layer
backgroundColor: "#fff"
borderRadius: 4
width: 200
height: 200
rotation: 0
layerA.center()
layerA.states.add
grow:
scale: 1.5
rotation: 90
shrink:
scale: 1
rotation: 0
layerA.states.animationOptions =
curve: "spring(400, 50, 30)"
layerA.onClick ->
layerA.states.next("grow", "shrink")
However, if I add the conditional below it is ignored?
if layerA.states.current is "grow"
layerA.states.animationOptions =
curve: "ease"
time: 2
else
layerA.states.animationOptions =
curve: "spring(400,50,30)"
Seems the Framer API has been updated and now the .name property must be appended to states.current for this to work.
So the following conditional
if layerA.states.current is "grow"
layerA.states.animationOptions =
curve: "ease"
time: 2
else
layerA.states.animationOptions =
curve: "spring(400,50,30)"
... would become
if layerA.states.current.name is "grow"
layerA.states.animationOptions =
curve: "ease"
time: 2
else
layerA.states.animationOptions =
curve: "spring(400,50,30)"
Related
In Flutter, if we use the ColorFilter widget, it takes a ColorFilter.matrix and an Image, on which it applies the ColorFilter.matrix.
const ColorFilter sepia = ColorFilter.matrix(<double>[
0.393, 0.769, 0.189, 0, 0,
0.349, 0.686, 0.168, 0, 0,
0.272, 0.534, 0.131, 0, 0,
0, 0, 0, 1, 0,
]);
Container _buildFilterThumbnail(int index, Size size) {
final Image image = Image.file(
widget.imageFile,
width: size.width,
fit: BoxFit.cover,
);
return Container(
padding: const EdgeInsets.all(4.0),
decoration: BoxDecoration(
border: Border.all(color: _selectedIndex == index ? Colors.blue : Theme.of(context).primaryColor, width: 4.0),
),
child: ColorFiltered(
colorFilter: ColorFilter.matrix(filters[index].matrixValues),
child: Container(
height: 80,
width: 80,
child: image,
),
),
);
}
How can we get the underlying image (in pixels/bytes) so that it can be saved on disk. I don't want to save the rendered ColorFiltered area on the screen.
Curretly am forced to use the photofilters library from pub.dev, which does the pixel manipulation to apply the custom filters. However, its not very efficient and essentially applies the pixel level manipulation for every thumbnail, making it very slow. On the other hand, ColorFiltered widget is lightening fast!
Below is internal working of photofilters library
int clampPixel(int x) => x.clamp(0, 255);
// ColorOverlay - add a slight color overlay.
void colorOverlay(Uint8List bytes, num red, num green, num blue, num scale) {
for (int i = 0; i < bytes.length; i += 4) {
bytes[i] = clampPixel((bytes[i] - (bytes[i] - red) * scale).round());
bytes[i + 1] =
clampPixel((bytes[i + 1] - (bytes[i + 1] - green) * scale).round());
bytes[i + 2] =
clampPixel((bytes[i + 2] - (bytes[i + 2] - blue) * scale).round());
}
}
// RGB Scale
void rgbScale(Uint8List bytes, num red, num green, num blue) {
for (int i = 0; i < bytes.length; i += 4) {
bytes[i] = clampPixel((bytes[i] * red).round());
bytes[i + 1] = clampPixel((bytes[i + 1] * green).round());
bytes[i + 2] = clampPixel((bytes[i + 2] * blue).round());
}
}
Any pointers appreciated.
I'm relatively new to Swift and have a grid layout question: I'm currently using a LazyHGrid with adaptive grid items and a single column to flexibly layout items without a predetermined column count. I determine the number of columns shown by setting a maxWidth the grid layout with a maxWidth based on the number of items to be displayed
What I'm trying to accomplish in each of the scenarios below (with a solution that would scale up too) is essentially to adjust the positions in the examples below by shifting items out of position "🔴" and into position "⚪️", eliminating the "floating orphan" item not hugging the edge. The "⚫️" positions are already correct.
CONSTRAINTS
I want to minimize the width that this grid uses, but not all rows can accommodate the taller stacks (so setting a bunch of brittle rules seems like a poor solution) and I'm not interested in setting a fixed row item height to remove the need for a dynamic solution
I'd like to avoid creating grid manually with nested HStacks and VStacks and writing a bunch of extra logic to manage the contents of each row and column given the height of the parent row (as retrieved via GeometryReader).
WHAT I'VE TRIED
I looked in the Lazy_Grid docs to see if there was a view modifier that would accomplish this -- didn't come across one (though it's entirely possible I've missed it!)
I thought maybe flipping the layoutDirection (from LTR to RTL) might do it, but no such luck
I shifted around the alignment values of the repeated gridItem and lazyHGrid container, but the floating orphan remained
EXAMPLES
For three items:
/* short */
___________
⚫️⚫️|
🔴⚪️|
/* tall */
___________
⚫️|
⚫️|
⚫️|
For four items:
/* short */
___________
⚫️⚫️|
⚫️⚫️|
/* tall */
___________ ___________
⚫️⚫️| ⚫️⚫️| // NOTE: I *could* constrain the height in this case
🔴⚪️| ⚫️⚫️| // to achieve the 2x2 grid but would rather not
🔴⚪️|
For five items:
/* short */
___________
⚫️⚫️⚫️|
🔴⚫️⚪️|
/* tall */
___________
⚫️⚫️|
⚫️⚫️|
🔴⚪️|
For six items:
/* short */
___________
⚫️⚫️⚫️|
⚫️⚫️⚫️|
/* tall */
___________
⚫️⚫️|
⚫️⚫️|
⚫️⚫️|
For seven items:
/* short */
___________
⚫️⚫️⚫️⚫️|
🔴⚫️⚫️⚪️|
/* tall */
___________
⚫️⚫️|
⚫️⚫️|
⚫️⚫️|
🔴⚪️|
let items = filterItems()
let iconCount = CGFloat(items.count)
let iconSize: CGFloat = 18
let spacing: CGFloat = 2
// NOTE: `iconCount / 2` because the min-height of the parent
// only fits two items. The current item count is 7 and it's
// unlikely that it'd ever do more than double.
let cols = CGFloat(iconCount / 2).rounded(.up)
let maxWidth = calcWidth(for: cols, iconSize: iconSize, spacing: spacing)
let minWidth = cols < 2 ? maxWidth : calcWidth(for: cols - 1, iconSize: iconSize, spacing: spacing)
LazyHGrid(
rows: Array(
repeating: GridItem(
.adaptive(minimum: iconSize, maximum: iconSize),
spacing: spacing,
alignment: .center
),
count: 1
),
alignment: .center,
spacing: spacing
) {
ForEach(0..<items.count, id: \.self) { n in
...item views...
}
}
.frame(minWidth: minWidth, maxWidth: maxWidth)
My brain is stuck on finding a Swift concept similar to CSS's FlexBox justify-content: flex-end; align-items: flex-start but it feels to me there should be a more Flexy/Swifty solution for this that I'm just missing?
(The grid is nested within an HStack currently, and shoved to the top-trailing corner of it's parent with a spacer, effectively accomplishing the align-items: flex-start portion of the Flexbox solution mentioned above asd as shown in the illustrations above)
Edit: Layout direction works for me
You mentioned this didn't work in your post, but I just tested setting layout direction to right-to-left, and it works. All the end items are aligned to the right. Maybe the specific OS you're testing on has a layout bug. The full playground snippet (tested on Xcode 13):
import UIKit
import PlaygroundSupport
import SwiftUI
import Foundation
let iconCount: CGFloat = 4
let iconSize: CGFloat = 18
let spacing: CGFloat = 2
let cols: CGFloat = 2
let maxWidth = calcWidth(for: cols, iconSize: iconSize, spacing: spacing)
let minWidth = cols < 2 ? maxWidth : calcWidth(for: cols - 1, iconSize: iconSize, spacing: spacing)
func calcWidth(for cols: CGFloat, iconSize: CGFloat, spacing: CGFloat) -> CGFloat {
return iconSize * cols + spacing * cols
}
PlaygroundPage.current.liveView = UIHostingController(rootView: {
TabView {
HStack {
LazyHGrid(
rows: Array(
repeating: GridItem(
.adaptive(minimum: iconSize, maximum: iconSize),
spacing: spacing,
alignment: .center
),
count: 1
),
alignment: .center,
spacing: spacing
) {
ForEach(0..<Int(iconCount), id: \.self) { n in
Text("B")
.frame(width: iconSize, height: iconSize)
.border(.red)
}
}
.frame(minWidth: minWidth, maxWidth: maxWidth)
.background(Color.green)
.frame(height: iconSize * 3 + spacing * 2)
.environment(\.layoutDirection, .rightToLeft)
// I also tried this, but it isn't needed
//.flipsForRightToLeftLayoutDirection(true)
}
}
}())
Original answer:
This is not the ideal solution, but one option is to use 3D rotation to flip the layout on the Y axis. I used a simple text view in Playgrounds as an example:
LazyHGrid(
rows: Array(
repeating: GridItem(
.adaptive(minimum: iconSize, maximum: iconSize),
spacing: spacing,
alignment: .center
),
count: 1
),
alignment: .center,
spacing: spacing
) {
ForEach(0..<Int(iconCount), id: \.self) { n in
Text("B")
.frame(width: iconSize, height: iconSize)
.rotation3DEffect(.degrees(180), axis: (x: 0, y: 1, z: 0))
}
}
.frame(minWidth: minWidth, maxWidth: maxWidth)
.rotation3DEffect(.degrees(180), axis: (x: 0, y: 1, z: 0))
If I want to convert a range from 0.0 to 1.0, into a range from 20.0 to 80.0, I can use lerpDouble(20.0, 80.0, animationValue).
How do I convert a range from 0.8 to 1.0, into a range from 0.0 to 1.0?
After some digging I found a simple solution to the problem:
final value = Interval(0.8, 1.0).transform(animationValue);
Dear you can use this plugging to animation in a flutter Here Link
You can use this:
(lerpDouble(0.8, 1.0, animationValue) * 1.0/0.2) - 4.0
When:
animationValue=0.8 => (0.8*5)-4.0 = 0.0
animationValue=1.0 => (1.0*5)-4.0 = 1.0
This is to do the other way round:
0.8 + 0.2 * lerpDouble(0.0, 1.0, animationValue)
When:
animationValue=0.0 => 0.8+(0.2*0) = 0.8
animationValue=1.0 => 0.8+(0.2*1) = 1.0
I was reading some tutorial of One simulator. I got one syntax that is
group.nodeLocation = 100,100
As far as I know a group can have multiple nodes. Therefore, I am not clear what does it mean by group.nodeLocation. Which node location we are fixing by using this command.
Thanks,
It depends on which kind of movement models you use.
Setting group.nodeLocation is required for StationaryMovement, but for other dynamic movement modes (e.g., RandomWaypoint) is meaningless.
If you want to set multiple nodes N with different location, you should separate it into N groups.
In speaking of adding static nodes in bulk, use MapRouterMovement to simulate it. The static node can be regarded as the initioal coordination equals the destination coordination. For instance, 5 static nodes are defined as:
LINESTRING (100 100, 100.0 100.0)
LINESTRING (200 200, 200.0 200.0)
LINESTRING (300 300, 300.0 300.0)
LINESTRING (400 400, 400.0 400.0)
LINESTRING (500 500, 500.0 500.0)
And the setting file like:
Group4.groupID = b
Group4.movementModel = MapRouteMovement #MapRouteMovement
Group4.routeFile = path/routFile.wkt #routeFile
Group4.routeType = 2
Group4.nrofHosts = 5
Group4.waitTime = 0, 0
Group4.speed = 0, 0
BTW, don't forget to group the above coordinations as a map file, seeing below:
#settings.txt
MapBasedMovement.nrofMapFiles = 1
MapBasedMovement.mapFile1 = path/mapFile.wkt
#mapFile.wkt
LINESTRING (100 100, 200.0 200.0, 300 300, 400 400, 500.0 500.0)
Basically, I need to create layers from five images. Is there a way to do this with a for loop, as opposed to manually creating the layers? The following code was my attempt, but I'm not sure how to debug from here.
tabs_strings = ["nearby", "adopted", "my_cats", "settings", "bruce"]
for tab in [0..tabs_strings]
tab = new Layer
x:0, y:0, width:640, height:1136, image:"images/#{tab}.jpg"
# nearby = new Layer
# x:0, y:0, width:640, height:1136, image:"images/nearby.jpg"
# adopted = new Layer
# x:0, y:0, width:640, height:1136, image:"images/adopted.jpg", opacity: 0
# my_cats = new Layer
# x:0, y:0, width:640, height:1136, image:"images/my_cats.jpg", opacity: 0
# settings = new Layer
# x:0, y:0, width:640, height:1136, image:"images/settings.jpg", opacity: 0
# bruce = new Layer
# x:0, y:0, width:640, height:1136, image:"images/bruce.jpg", opacity: 0
Your for loop is, um, strange. tabs_strings is itself an array so you're saying:
for i in [0 .. some_array]
rather than the usual:
for i in [0 .. some_number]
or
for e in some_array
If you look at the JavaScript version, you'll see this:
for (tab = _i = 0; 0 <= tabs_strings ? _i <= tabs_strings : _i >= tabs_strings; tab = 0 <= tabs_strings ? ++_i : --_i) {
so you end up comparing 0 with an array and that's not terribly productive.
I think you want to use the for e in array form of the for-loop:
for tab in tab_strings
new Layer
x:0, y:0, width:640, height:1136, image:"images/#{tab}.jpg"
There's no need for the tab assignment inside the loop so I took that out.
Is your question that the code you posted does not work and that you are looking for an alternative solution?
EDIT:
The only problem I see here is that you are using "tab" for both the string variable passed from the current position in the array, as well the new Layer object that you are initializing.
Try this:
tabs_strings = ["nearby", "adopted", "my_cats", "settings", "bruce"]
for tab in [0..tabs_strings.length]
tabLayer = new Layer
x:0, y:0, width:640, height:1136, image:"images/#{tab}.jpg"