I recently switched from using PaintCode 2 to PaintCode 3, I am using it together with xCode/Swift.
I noticed however, that all my image generating functions not behave differently. They seam to standard addopt cap insets.
As an example below you can find one canvas "ViewMissingImage", and how its configured in PaintCode (2 or 3 its identical).
Code generated via PaintCode 2
public class func imageOfViewMissingImage(frame frame: CGRect = CGRect(x: 6, y: 5, width: 109, height: 109)) -> UIImage {
UIGraphicsBeginImageContextWithOptions(frame.size, false, 0)
PaintCode.drawViewMissingImage(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
let imageOfViewMissingImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return imageOfViewMissingImage
}
Code generated via PaintCode 3
public dynamic class func imageOfViewMissingImage(imageSize imageSize: CGSize = CGSize(width: 109, height: 109)) -> UIImage {
UIGraphicsBeginImageContextWithOptions(imageSize, false, 0)
PaintCode.drawViewMissingImage(frame: CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height))
let imageOfViewMissingImage = UIGraphicsGetImageFromCurrentImageContext()!.resizableImageWithCapInsets(UIEdgeInsetsZero, resizingMode: .Tile)
UIGraphicsEndImageContext()
return imageOfViewMissingImage
}
I think that the PaintCode 2 never used the capp insets, maybe it was a bug?
I do not want these cap insets, how can I get rid of them?
The solution is straightforward:
Put the Cap Inset on "Stretch" instead of tile in PaintCode UI!
Related
Here's what I need to do: I have a parent view with a fixed width and 4 children. 2 of the children (1st and 3rd) have fixed width. The others (2nd and 4th) have flexible width. The default interpretation for flexible is that they would share equally the space available, but I don't want this, instead, I want to tell each flexible View how much of the remaining space it should take, for instance, the first should take 2/3 and the second 1/3.
For people familiar with the Flex Layout, this is equivalent to say I want my 2nd View to have flex: 2 and my 4th view to have flex: 1. See the example below:
In the example above, the parent view has the fixed width of 600px. The first child has 100px width, the third has 140px. The remaining space is 360px, so the second child gets 240px (2/3) and the fourth child gets 120px(1/3). If I change the width of the parent view, the size of the second and fourth children will adapt accordingly.
It is extremely simple to do this for the Web, see the code below:
<div style="width: 600; display: flex; flex-direction: row;">
<div style="width: 100; height: 100; background-color: red;"></div>
<div style="flex: 2; height: 100; background-color: green;"></div>
<div style="width: 140; height: 100; background-color: blue;"></div>
<div style="flex: 1; height: 100; background-color: purple;"></div>
</div>
It is also super-simple to do it in Flutter:
Row(
children: [
Container(height: 50, width: 50, color: Colors.red),
Flexible(flex: 2, child: Container(height: 50, color: Colors.green)),
Container(height: 50, width: 80, color: Colors.blue),
Flexible(flex: 1, child: Container(height: 50, color: Colors.purple)),
]
)
It's very similar in Jetpack Compose (Android):
Row {
Row(modifier = Modifier.height(50.dp).width(50.dp).background(color = Color.Red)) {}
Row(modifier = Modifier.height(50.dp).weight(2F).background(color = Color.Green)) {}
Row(modifier = Modifier.height(50.dp).width(80.dp).background(color = Color.Blue)) {}
Row(modifier = Modifier.height(50.dp).weight(1F).background(color = Color.Black)) {}
}
I tried a lot of things, but I couldn't find any simple way of achieving this behavior in SwiftUI. From my understanding, to size the children, SwiftUI first calculates the size of every child that can have its size calculated, i.e. every child that has a fixed size, after that it calculates the remaining space and divide it by the number of children with an undefined size telling each of them this is the maximum size they can occupy (this is the size we read when using a GeometryReader). Is there a way to tell SwiftUI to not divide the space available equally among the children with undefined size, but instead divide it according to a factor specified by each one of them?
Is there a different approach to this in a way I can obtain the same result as the other platforms I mentioned here?
For now, my strategy is much more complex than I'd like it to be. I render the first child with width = 50, the second child with width = 0 (should be flexible), the third child with width = 80, the fourth child with width = 0 (should be flexible) and an additional 5th child with width = .infinity. After the first render, I measure the size of the 5th child and update a state with this value, which represents the remaining space after the children with fixed size have been placed. After the state is updated, I can calculate the sizes of the flexible children and render everything a second time, now with the correct sizes. See the code below:
struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {}
}
struct ContentView: View {
private let totalFlexFactor = 3
#State private var freeSpace: CGSize? = nil
func getFlexibleWidth(parentWidth: CGFloat, factor: Int) -> CGFloat {
return (CGFloat(factor) / CGFloat(totalFlexFactor)) * (freeSpace?.width ?? 0)
}
var body: some View {
GeometryReader { parentGeometry in
HStack(spacing: 0) {
HStack() {}
.frame(maxWidth: 50, maxHeight: .infinity)
.background(Color.red)
HStack() {}
.frame(maxWidth: getFlexibleWidth(parentWidth: parentGeometry.size.width, factor: 2), maxHeight: .infinity)
.background(Color.green)
HStack() {}
.frame(maxWidth: 80, maxHeight: .infinity)
.background(Color.blue)
HStack() {}
.frame(maxWidth: getFlexibleWidth(parentWidth: parentGeometry.size.width, factor: 1), maxHeight: .infinity)
.background(Color.purple)
if (freeSpace == nil) {
HStack() {}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(
GeometryReader { geometryProxy in
Color.clear
.preference(key: SizePreferenceKey.self, value: geometryProxy.size)
}
)
}
}
.frame(maxWidth: .infinity, maxHeight: 50)
.background(Color.gray)
.onPreferenceChange(SizePreferenceKey.self) { newSize in
if (freeSpace == nil) {
freeSpace = newSize
}
}
}
}
}
Credits to Federico Zanetello for the code that measures the size of the children.
As I said before, I don't see this as a very elegant solution, mainly if we compare it to the other platforms. I'd appreciate any suggestion! Just keep in mind the example I gave: fixed sized views intercalated with flexibly sized views.
Edit: I'm trying to build a component called Flexbox. In my example, I set the widths of each view, but it's just for simplicity. In fact, inside the Flexbox component, I don't know the size of any of the children, that's why, in my solution, I had to measure them.
Example: I might call:
Flexbox {
ViewWith100Width()
Flexible(flex: 2) { ViewWithFlexibleSize() }
ViewWith80Width()
Flexible(flex: 1) { AnotherViewWithFlexibleSize() }
}
But I could also call:
Flexbox {
ViewWith40Width()
Flexible(flex: 2) { ViewWithFlexibleSize() }
ViewWith60Width()
Flexible(flex: 1) { AnotherViewWithFlexibleSize() }
}
The component Flexbox must be agnostic of the size of whichever child is passed to it. That's why I had to measure each non-flexible child.
I haven't mentioned this in the original formulation of the question because I didn't want to overcomplicate it, since I just want to know if there's an easier way to simulate the Flexbox behavior of web/flutter/compose in swiftui.
While I think PreferenceKeys are a great tool to have and use, this is not a case where they are needed. Your plan was overly complicated. This comes down to a simple math problem, but first there is a coding issue:
.frame(maxWidth: 50, maxHeight: .infinity)
gives you a flexible, not a fixed width. What you have told ViewBuilder to do is assign to the width of the frame any value up to 50, not a value of 50. I understand what you were doing, as you wanted to expand the height to the size of the view container. There are two alternatives:
.frame(minWidth: 50, maxWidth: 50, maxHeight: .infinity)
or
.frame(width: 50)
.frame(maxHeight: .infinity)
I chose the latter as it makes your intention very clear. Since they were fixed, I also assigned them to let constants to be used anywhere I needed them.
Also, while I did not test this, I suspect the PreferenceKey couldn't handle the disappearing/reappearing view. Since they were unnecessary, it didn't delve into it.
At this point, you can find your flexible space simply by parentGeometry less the two fixed widths. No PreferenceKeys needed. in the end, the code simplifies to:
struct ContentView: View {
private let totalFlexFactor: CGFloat = 3
#State private var freeSpace: CGSize? = nil
private let width1: CGFloat = 100
private let width2: CGFloat = 80
private func getFlexibleWidth(parentWidth: CGFloat, factor: CGFloat) -> CGFloat {
((parentWidth - (width1 + width2)) / totalFlexFactor) * factor
}
var body: some View {
GeometryReader { parentGeometry in
HStack(spacing: 0) {
HStack {
Text(width1.description)
}
.frame(width: width1)
.frame(maxHeight: .infinity)
.background(Color.red)
HStack {
Text(getFlexibleWidth(parentWidth: parentGeometry.size.width, factor: 2).description)
}
.frame(maxWidth: getFlexibleWidth(parentWidth: parentGeometry.size.width, factor: 2), maxHeight: .infinity)
.background(Color.green)
HStack {
Text(width2.description)
}
.frame(width: width2)
.frame(maxHeight: .infinity)
.background(Color.blue)
HStack {
Text(getFlexibleWidth(parentWidth: parentGeometry.size.width, factor: 1).description)
}
.frame(maxWidth: getFlexibleWidth(parentWidth: parentGeometry.size.width, factor: 1), maxHeight: .infinity)
.background(Color.purple)
}
.frame(maxWidth: .infinity, maxHeight: 50)
.background(Color.gray)
}
}
}
I also displayed the values for the widths of the various HStacks in the HStacks.
Also, with regard to SwiftUI syntax, it is not necessary to write HStack() unless you intend to use the optional values of alignment: and spacing:, otherwise we omit the ().
The main idea in to layout is where to use needed containers. Here (fixed-flex-fixed-flex) GeometryReader can be used only for three.
Tested with Xcode 13.3 / iOS 15.4
Main idea part is:
GeometryReader { gp in
HStack (spacing: 0) {
Color.green
.frame(width: (gp.size.width - fixed2) * 2/3)
Color.blue
.frame(width: fixed2)
Completed findings and report is here
Try .layoutPriority(1/0) to have grow and shrink behaviour
setting priority 1, lets view grow and shrink
I am drawing a line with Path, and on that line I want to have a circle if I play around I can get the circle on the line of course. However I do not understand why this code does not put the circle on the line:
struct CircleOnLineView: View {
func createCirle() -> some View {
return Circle().fill(Color.blue)
}
var body: some View {
GeometryReader { geometry in
ZStack {
Path { path in
path.move(to: CGPoint(x: 0, y: geometry.size.height / 2))
path.addLine(to: CGPoint(x: geometry.size.width, y: geometry.size.height / 2))
}
.stroke(Color.gray, lineWidth: 3)
Circle()
.fill(Color.blue)
.position(CGPoint(x: 0 , y: geometry.size.height / 2))
.frame(width: 5, height: 5)
}
}
}
}
Order of modifiers in this case is important. Here is how it is expected (1st - made size of shape, 2nd - position it):
Circle()
.fill(Color.blue)
.frame(width: 5, height: 5)
.position(CGPoint(x: 0 , y: geometry.size.height / 2))
I am using react-native-navigation and trying to add a native view on the top of everything. I initialized the Swift class in AppDelegate and call swift func:
func showUp() {
let window = UIApplication.shared.keyWindow!
let rect = UIView(frame: CGRect(x: 50, y: 50, width: 100, height: 50))
rect.backgroundColor = UIColor.white
window.addSubview(rect) }
The View seemed to be appeared while loading app and then disappears after app is
loaded.
Thanks in advance)
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Im working on a project of building a editor, i am using the Fabric.js, but i don know how to make the canvas object auto align.
Is there any example of making canvas object auto align with another object like this?
image of snap example
auto snap example from other site
link here:
auto snap example site
I was working on the same thing. This seems to be a pretty common feature request so I thought I'd share what I worked out. It could use some refinement. For instance, I've noticed if you scale the red box, the scale is not applied and it doesn't align right. However, I think it demonstrates the basic principal well and you can elaborate on it to fit your needs.
(Note: 8/1/2017: Working to place a more comprehensive code base on GitHub. (https://github.com/JerrodV/FabricObjectAlignment) More Details Soon!)
You can view the fiddle [here][1]
Html:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<canvas id="c" height="600" width="600" style="border:1px solid #c1c1c1;"></canvas>
</div>
</form>
<script src="Scripts/jquery-3.1.1.min.js"></script>
<script src="Scripts/fabric.min.js"></script>
<script src="Scripts/default.js"></script>
</body>
</html>
Javascript:
Def = {
canvas: null,
rect: null,
lines: {
top: null,
left: null,
right: null,
bottom: null
},
init: function () {
Def.canvas = new fabric.Canvas('c');
Def.canvas.on('object:moving', Def.events.objectMoving);
Def.canvas.add(new fabric.Rect({
height: 100,
width: 100,
top: 100,
left: 200,
fill: 'black',
selectable: false
}));
Def.canvas.add(new fabric.Rect({
height: 100,
width: 100,
top: 300,
left: 100,
fill: 'black',
selectable: false
}));
Def.rect = new fabric.Rect({
height: 100,
width: 100,
top: 200,
left: 250,
fill: 'red'
});
Def.canvas.add(Def.rect);
},
events: {
objectMoving: function (e) {
//Get the object being manipulated
var obj = e.target;
//Set up an object representing its current position
var curPos = {
top: parseInt(obj.get('top')),
left: parseInt(obj.get('left')),
right: parseInt(obj.get('left') + obj.get('width')),
bottom: parseInt(obj.get('top') + obj.get('height'))
};
//Set up an object that will let us be able to keep track of newly created lines
var matches = {
top: false,
left: false,
right: false,
bottom: false
}
//Get the objects from the canvas
var objects = Def.canvas.getObjects();
//For each object
for (var i in objects) {
//If the object we are looing at is a line or the object being manipulated, skip it
if (objects[i] === obj || objects[i].get('type') === 'line') { continue; }
//Set up an object representing the position of the canvas object
var objPos = {
top: parseInt(objects[i].get('top')),
left: parseInt(objects[i].get('left')),
right: parseInt(objects[i].get('left') + obj.get('width')),
bottom: parseInt(objects[i].get('top') + obj.get('height'))
}
//Look at all 4 sides of the object and see if the object being manipulated aligns with that side.
//Top////////////////////////////////////
if (Def.inRange(objPos.top, curPos.top)) {
//We match. If we don't already have aline on that side, add one.
if (!Def.lines.top) {
Def.drawLine('top', objPos.top);
//Keep track of the fact we found a match so we don't remove the line prematurely.
matches.top = true;
//Snap the object to the line
obj.set('top', objPos.top).setCoords();
}
}
//Left////////////////////////////////////
if (Def.inRange(objPos.left, curPos.left)) {
if (!Def.lines.left) {
Def.drawLine('left', objPos.left);
matches.left = true;
obj.set('left', objPos.left).setCoords();
}
}
//Right////////////////////////////////////
if (Def.inRange(objPos.right, curPos.right)) {
if (!Def.lines.right) {
Def.drawLine('right', objPos.right);
matches.right = true;
obj.set('left', objPos.right - objects[i].get('width')).setCoords();
}
}
//Bottom////////////////////////////////////
if (Def.inRange(objPos.bottom, curPos.bottom)) {
if (!Def.lines.bottom) {
Def.drawLine('bottom', objPos.bottom);
matches.bottom = true;
obj.set('top', objPos.bottom - objects[i].get('height')).setCoords();
}
}
//Look at the side we matched on. If we did not match, and we have a line, remove the line.
for (var j in matches) {
var m = matches[j];
var line = Def.lines[j];
if (!m && line) {
Def.canvas.remove(line);
Def.lines[j] = null;
}
}
}
Def.canvas.renderAll();
}
},
drawLine: function (side, pos) {
var ln = null
switch (side) {
case 'top':
ln = new fabric.Line([Def.canvas.get('width'), 0, 0, 0], {
left: 0,
top: pos,
stroke: 'rgb(178, 207, 255)'
});
Def.lines.top = ln;
break;
case 'left':
ln = new fabric.Line([0, Def.canvas.get('height'), 0, 0], {
left: pos,
top: 0,
stroke: 'rgb(178, 207, 255)'
});
Def.lines.left = ln;
break;
case 'right':
ln = new fabric.Line([0, Def.canvas.get('height'), 0, 0], {
left: pos,
top: 0,
stroke: 'rgb(178, 207, 255)'
});
Def.lines.right = ln;
break;
case 'bottom':
ln = new fabric.Line([Def.canvas.get('width'), 0, 0, 0], {
left: 0,
top: pos,
stroke: 'rgb(178, 207, 255)'
});
Def.lines.bottom = ln;
break;
}
Def.canvas.add(ln).renderAll();
},
alignTolerance : 6,
inRange: function (val1, val2) {
if ((Math.max(val1, val2) - Math.min(val1, val2)) <= Def.alignTolerance) { return true; }
else { return false; }
}
};
$(Def.init);
I hope you find this useful. Good Luck!
[1]: https://jsfiddle.net/cLy86rtd/
Hello friends,
I am developing a functionality to display index number on map pin and set image on mapview of iPhone so please tell me any link or any idea to develop this functionality.
Thanks in advance.
What is an index number in the context? Is it just a digit that your code is displaying? If so your question is how to display text on a map. Use a map overlay. Same for images. Search for MKMapOverlay and go from there.
I have use this method for index number in annotation view.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else {
return nil
}
// Better to make this class property
let annotationIdentifier = "AnnotationIdentifier"
var annotationView = MKAnnotationView()
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
annotationView.frame = CGRect(x: annotationView.frame.origin.x, y: annotationView.frame.origin.y, width: 80, height: 200)
annotationView.annotation = annotation
annotationView.tag = index
index += 1
let imageViewPin = UIImageView(frame: CGRect(x: 0, y: 0, width: 30, height: 40))
imageViewPin.center = CGPoint(x: annotationView.center.x, y: annotationView.center.y - 11)
imageViewPin.image = UIImage(named: "green_pin")
annotationView.addSubview(imageViewPin)
return annotationView
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
debugPrint(view.tag)
}