Programmatically setting constraint in iOS makes button disappear - nslayoutconstraint

I have this code, and when I uncomment the block the button is gone, and commented it is visible.When uncommented
var fab:UIButton = UIButton(type: .custom)
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
self.title = "Maintain My Vehicle"
let vehicleInfoController = VehicleInfoController()
vehicleInfoController.tabBarItem = UITabBarItem(tabBarSystemItem: .favorites, tag: 0)
let vehicleLogsController = VehicleLogsController()
vehicleLogsController.tabBarItem = UITabBarItem(tabBarSystemItem: .bookmarks, tag: 2)
let viewControllerList = [ vehicleInfoController, vehicleLogsController ]
viewControllers = viewControllerList.map { UINavigationController(rootViewController: $0) }
floatingButton()
let centerLabel = UILabel()
// Don't forget this!
centerLabel.translatesAutoresizingMaskIntoConstraints = false
centerLabel.text = "Perfectly centered!"
view.addSubview(centerLabel)
NSLayoutConstraint.activate([
centerLabel.centerXAnchor.constraint(
equalTo: view.centerXAnchor, constant: 0),
centerLabel.centerYAnchor.constraint(
equalTo: view.centerYAnchor, constant: 0)
])
/*
fab.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
fab.centerXAnchor.constraint(
equalTo: view.centerXAnchor, constant: 0),
fab.centerYAnchor.constraint(
equalTo: view.bottomAnchor, constant: 0)
])
*/
}
func floatingButton(){
fab = UIButton(type: .custom)
fab.frame = CGRect(x: 150, y: 600, width: 75, height: 75)
fab.setTitle("+", for: .normal)
fab.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
fab.clipsToBounds = true
fab.layer.cornerRadius = 50
fab.layer.borderColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
fab.layer.borderWidth = 3.0
fab.layer.masksToBounds = true
fab.layer.zPosition = 1
fab.addTarget(self, action:#selector(self.buttonClicked), for: .touchUpInside)
view.addSubview(fab)
}
When commented
I have no idea why the center label is fine but my button is messed up.

Your problem is fab.centerYAnchor.constraint(equalTo: view.bottomAnchor), even though bottomAnchor does conforms to NSLayoutYAxisAnchor, but I haven't seen this combination, instead centerY connects with another centerY anchor.
What you can do is to embed the button in a view and constraint this view from centerLabel.bottomAnchor and view.bottomAnchor, like so:
func floatingButton(centerLabel: UIView) {
let fabView = UIView()
fabView.backgroundColor = .red
fabView.layer.zPosition = 1
fab = UIButton(type: .custom)
fab.setTitle("+", for: .normal)
fab.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
fab.clipsToBounds = true
fab.layer.cornerRadius = 50
fab.layer.borderColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
fab.layer.borderWidth = 3.0
fab.layer.masksToBounds = true
fabView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(fabView)
fab.translatesAutoresizingMaskIntoConstraints = false
fabView.addSubview(fab)
NSLayoutConstraint.activate([
centerLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0),
centerLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0),
fabView.topAnchor.constraint(equalTo: centerLabel.bottomAnchor),
fabView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
fabView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
fabView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
fab.centerXAnchor.constraint(equalTo: fabView.centerXAnchor, constant: 0),
fab.centerYAnchor.constraint(equalTo: fabView.centerYAnchor, constant: 0),
fab.widthAnchor.constraint(equalToConstant: 75),
fab.heightAnchor.constraint(equalToConstant: 75),
])
}
Following is just the cleaned up viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Maintain My Vehicle"
self.view.backgroundColor = UIColor.white
let vehicleInfoController = UIViewController()
vehicleInfoController.tabBarItem = UITabBarItem(tabBarSystemItem: .favorites, tag: 0)
let vehicleLogsController = UIViewController()
vehicleLogsController.tabBarItem = UITabBarItem(tabBarSystemItem: .bookmarks, tag: 2)
let viewControllerList = [ vehicleInfoController, vehicleLogsController ]
self.viewControllers = viewControllerList.map { UINavigationController(rootViewController: $0) }
let centerLabel = UILabel()
centerLabel.text = "Perfectly centered!"
centerLabel.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(centerLabel)
floatingButton(centerLabel: centerLabel)
}
That yields

Related

Cutting one shape from an other shape in Jetpack Compose

I had a question about making this view in Compose and I have no idea about implementing it.
My current code looks like this:
Box(
modifier = Modifier
.fillMaxSize()
.height(300.dp)
) {
Canvas(modifier = Modifier.matchParentSize()) {
drawRoundRect(
color = Color.Yellow,
cornerRadius = CornerRadius(16.dp.toPx(), 16.dp.toPx())
)
drawRoundRect(
color = Color.White,
topLeft = Offset(
x = size.width / 5,
y = size.height - 60.dp.toPx()
),
size = Size((size.width / 5) * 3, 50.dp.toPx() * 2),
cornerRadius = CornerRadius(24.dp.toPx(), 24.dp.toPx()),
)
}
Box(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
Text(
text = "Test",
modifier = Modifier.align(Alignment.BottomCenter)
)
}
}
Result is the following:
To clip some path from an other path, you can use clipPath.
And to outer corner radius, you need to add arcs to the path manually, like this:
Canvas(modifier = Modifier.matchParentSize()) {
val outerCornerRadius = 16.dp.toPx()
val clippedPath = Path().apply {
val innerCornerRadius = 24.dp.toPx()
val rectSize = Size(round((size.width / 5) * 3), round(50.dp.toPx() * 2))
val rect = Rect(
offset = Offset(
x = (size.width - rectSize.width) / 2,
y = size.height - rectSize.height
),
size = rectSize
)
addRoundRect(
RoundRect(
rect,
topLeft = CornerRadius(x = innerCornerRadius, y = innerCornerRadius),
topRight = CornerRadius(x = innerCornerRadius, y = innerCornerRadius),
)
)
val outerCornerDiameter = outerCornerRadius * 2
val cornerSize = Size(outerCornerDiameter,outerCornerDiameter)
val cornerOffset = Offset(outerCornerDiameter, outerCornerDiameter)
val cornerYOffset = Offset(0f, outerCornerDiameter)
moveTo(rect.bottomLeft - cornerYOffset)
addArc(
Rect(
offset = rect.bottomLeft - cornerOffset,
size = cornerSize
),
startAngleDegrees = 0f,
sweepAngleDegrees = 90f,
)
lineTo(rect.bottomLeft)
moveTo(rect.bottomRight - cornerYOffset)
addArc(
Rect(
offset = rect.bottomRight - cornerYOffset,
size = cornerSize
),
startAngleDegrees = 180f,
sweepAngleDegrees = -90f,
)
lineTo(rect.bottomRight)
}
clipPath(clippedPath, clipOp = ClipOp.Difference) {
drawRoundRect(
color = Color.Yellow,
cornerRadius = CornerRadius(outerCornerRadius, outerCornerRadius)
)
}
}
Result:
Also you can use a custom Shape for your Composables to give them a specific outline. Just extend the Shape interface and override the createOutline() method.
Example:
For the corners, the Path API offers a function arcTo(). Then, to draw the edges of the shape, use the lineTo() method.
class RoundedRectOutlinedCorner(
private val cornerRadius: Dp = 16.dp,
private val cutOutHeight: Dp = 60.dp,
private val cutOutWidth: Dp = 145.dp
) : Shape {
override fun createOutline(
size: Size, layoutDirection: LayoutDirection, density: Density
): Outline {
return Outline.Generic(Path().apply {
val cornerRadius = with(density) { cornerRadius.toPx() }
val cutOutHeight = with(density) { cutOutHeight.toPx() }
val cutOutWidth = with(density) { cutOutWidth.toPx() }
arcTo(
rect = Rect(offset = Offset(0f, 0f), Size(cornerRadius, cornerRadius)),
startAngleDegrees = 180f,
sweepAngleDegrees = 90f,
forceMoveTo = false
)
lineTo(size.width - cutOutWidth - cornerRadius, 0f)
arcTo(
rect = Rect(
offset = Offset(size.width - cutOutWidth - cornerRadius, 0f),
Size(cornerRadius, cornerRadius)
), startAngleDegrees = 270.0f, sweepAngleDegrees = 90f, forceMoveTo = false
)
lineTo(size.width - cutOutWidth, cutOutHeight - cornerRadius)
arcTo(
rect = Rect(
offset = Offset(size.width - cutOutWidth, cutOutHeight - cornerRadius),
Size(cornerRadius, cornerRadius)
), startAngleDegrees = 180.0f, sweepAngleDegrees = -90f, forceMoveTo = false
)
lineTo(size.width - cornerRadius, cutOutHeight)
arcTo(
rect = Rect(
offset = Offset(size.width - cornerRadius, cutOutHeight),
Size(cornerRadius, cornerRadius)
), startAngleDegrees = 270f, sweepAngleDegrees = 90f, forceMoveTo = false
)
lineTo(size.width, size.height - cornerRadius)
arcTo(
rect = Rect(
offset = Offset(size.width - cornerRadius, size.height - cornerRadius),
Size(cornerRadius, cornerRadius)
), startAngleDegrees = 0f, sweepAngleDegrees = 90f, forceMoveTo = false
)
lineTo(cornerRadius, size.height)
arcTo(
rect = Rect(
offset = Offset(0f, size.height - cornerRadius),
Size(cornerRadius, cornerRadius)
), startAngleDegrees = 90f, sweepAngleDegrees = 90f, forceMoveTo = false
)
close()
})
}
}
Usage:
Then, you can clip a shape with:
Modifier
.height(250.dp)
.clip(RoundedRectOutlinedCorner()),
Or with .graphicsLayer/.background etc.
Result:

Setting SKLabelNode to centre of SKSpriteNode Swift

I'm trying to set a SKLabelNode's position to the center of a SKSpriteNode.
I've looked at other questions on this but none of these work with Swift 3.
This is my code:
var letter1background = SKSpriteNode(imageNamed: "letterbackground")
var letter1text = SKLabelNode()
override func didMove(to view: SKView) {
letter1background.position = CGPoint(x: self.size.width / 8, y: self.size.height / 7.5)
letter1background.size = CGSize(width: self.size.width / 8, height: self.size.width / 8)
letter1background.zPosition = -5
self.addChild(letter1background)
letter1text.text = "C"
letter1text.fontName = "Verdana-Bold "
letter1text.fontSize = 28
letter1text.fontColor = UIColor.white
letter1text.zPosition = 0
letter1text.horizontalAlignmentMode = letter1background.center
letter1text.verticalAlignmentMode = letter1background.center
self.letter1background.addChild(letter1text)
}
This code looks like it would work but in Swift 3 I now get this error:
Value of type 'SKSpriteNode' has no member 'center'
I have also tried:
self.letter1text.position = CGPoint(x: letter1background.frame.width/2 - (letter1text.frame.width/2), y: letter1background.frame.height/2 -(letter1text.frame.height/2))
&
letter1text.position = CGPoint(x:letter1background.frame.midX, y:letter1background.frame.midY)
But I still get results like this:
Any ideas?
Your calculations of label's position are wrong. You just have to add a label to the at 0,0 position and it will be centered because of SpriteKit's coordinate system rules (0,0 is at the center of the node).
override func didMove(to view: SKView) {
let label = SKLabelNode(fontNamed: "Arial")
label.text = "C"
label.fontColor = .black
label.verticalAlignmentMode = .center
label.fontSize = 29.0
label.zPosition = 1
let background = SKSpriteNode(color: .green, size: CGSize(width: 50, height: 50))
background.addChild(label)
addChild(background)
}
And you will get this:

Swift 3 and CGContextDrawImage

I want to translate this line to the Swift 3 current syntax code but seems there are some problems:
CGContextDrawImage(context, CGRect(x:0.0,y: 0.0,width: image!.size.width,height: image!.size.height), image!.cgImage)
According to the CoreGraphics.apinotes CGContextDrawImage was converted to CGContext.draw :
Name: CGContextDrawImage
# replaced by draw(_ image: CGImage, in rect: CGRect, byTiling: Bool = false)
SwiftName: CGContext.__draw(self:in:image:)
SwiftPrivate: true
When I try to do :
CGContext.draw(context as! CGImage, in: CGRect(x:0.0, y:0.0, width: image!.size.width, height: image!.size.height), byTiling: false)
Seems there is some simple syntax that disturb the compiler but I cannot see (in fact I receive a typical ambiguous error):
Can anyone help me with this new swift 3 syntax code?
You need to call it as if it's an instance method of CGContext:
context.draw(image!.cgImage!, in: CGRect(x: 0.0,y: 0.0,width: image!.size.width,height: image!.size.height))
Check the latest reference of CGContext.
I have found an another very good solution for this issue which i am using currently. You just need to pass the image as an arugument to this method after capturing image using UIImagePickerController. It works well for all version of iOS and also for both portrait and landscape orientations of Camera. It checks for EXIF property of image using UIImageOrientaiton and accordind to the value of orientation, it transforms & scales the image so you will get the same return image with same orientation as your camera view orientation.
Here i have kept maximum resolutions of 3000 so that the image quality doesn't get spoiled specially while you are using retina devices but you can change its resolution as per your requirement.
func scaleAndRotateImage(image: UIImage, MaxResolution iIntMaxResolution: Int) -> UIImage {
let kMaxResolution = iIntMaxResolution
let imgRef = image.cgImage!
let width: CGFloat = CGFloat(imgRef.width)
let height: CGFloat = CGFloat(imgRef.height)
var transform = CGAffineTransform.identity
var bounds = CGRect.init(x: 0, y: 0, width: width, height: height)
if Int(width) > kMaxResolution || Int(height) > kMaxResolution {
let ratio: CGFloat = width / height
if ratio > 1 {
bounds.size.width = CGFloat(kMaxResolution)
bounds.size.height = bounds.size.width / ratio
}
else {
bounds.size.height = CGFloat(kMaxResolution)
bounds.size.width = bounds.size.height * ratio
}
}
let scaleRatio: CGFloat = bounds.size.width / width
let imageSize = CGSize.init(width: CGFloat(imgRef.width), height: CGFloat(imgRef.height))
var boundHeight: CGFloat
let orient = image.imageOrientation
// The output below is limited by 1 KB.
// Please Sign Up (Free!) to remove this limitation.
switch orient {
case .up:
//EXIF = 1
transform = CGAffineTransform.identity
case .upMirrored:
//EXIF = 2
transform = CGAffineTransform.init(translationX: imageSize.width, y: 0.0)
transform = transform.scaledBy(x: -1.0, y: 1.0)
case .down:
//EXIF = 3
transform = CGAffineTransform.init(translationX: imageSize.width, y: imageSize.height)
transform = transform.rotated(by: CGFloat(Double.pi / 2))
case .downMirrored:
//EXIF = 4
transform = CGAffineTransform.init(translationX: 0.0, y: imageSize.height)
transform = transform.scaledBy(x: 1.0, y: -1.0)
case .leftMirrored:
//EXIF = 5
boundHeight = bounds.size.height
bounds.size.height = bounds.size.width
bounds.size.width = boundHeight
transform = CGAffineTransform.init(translationX: imageSize.height, y: imageSize.width)
transform = transform.scaledBy(x: -1.0, y: 1.0)
transform = transform.rotated(by: CGFloat(Double.pi / 2) / 2.0)
break
default: print("Error in processing image")
}
UIGraphicsBeginImageContext(bounds.size)
let context = UIGraphicsGetCurrentContext()
if orient == .right || orient == .left {
context?.scaleBy(x: -scaleRatio, y: scaleRatio)
context?.translateBy(x: -height, y: 0)
}
else {
context?.scaleBy(x: scaleRatio, y: -scaleRatio)
context?.translateBy(x: 0, y: -height)
}
context?.concatenate(transform)
context?.draw(imgRef, in: CGRect.init(x: 0, y: 0, width: width, height: height))
let imageCopy = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return imageCopy!
}

Detecting Shake Gesture by CoreMotion

I want to detect device shake using coreMotion framework for iOS 7. Can anyone help me out how to do this ?
I wrote code described below in my viewDidAppear
CMMotionManager *motionManager = [[CMMotionManager alloc] init];
motionManager.deviceMotionUpdateInterval = 1.0/60.0;
__block double myAcceleration;
[motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue]
withHandler:^(CMDeviceMotion *motion, NSError *error)
{
myAcceleration = motion.userAcceleration.y;
CATransform3D transform;
transform = CATransform3DMakeRotation(
motion.attitude.pitch, 1, 0, 0);
transform = CATransform3DRotate(transform,
motion.attitude.roll, 0, 1, 0);
transform = CATransform3DRotate(transform,
motion.attitude.yaw, 0, 0, 1);
}
];
but not detecting shake.
#define accelerationThreshold 0.30
- (void)motionMethod:(CMDeviceMotion *)deviceMotion
{
CMMotionManager *motionManager = [[CMMotionManager alloc] init];
CMAcceleration userAcceleration = deviceMotion.userAcceleration;
if (fabs(userAcceleration.x) > accelerationThreshold || fabs(userAcceleration.y) > accelerationThreshold || fabs(userAcceleration.z) > accelerationThreshold)
{
float sensitivity = 1;
float x1 = 0, x2 = 0, y1 = 0, y2 = 0, z1 = 0, z2 = 0;
double totalAccelerationInXY = sqrt(userAcceleration.x * userAcceleration.x +
userAcceleration.y * userAcceleration.y);
if (0.85 < totalAccelerationInXY < 3.45) {
x1 = userAcceleration.x;
y1 = userAcceleration.y;
z1 = userAcceleration.z;
float change = fabs(x1-x2+y1-y2+z1-z2);
if (sensitivity < change) {
// print change in position in coordinates.
NSLog (#"total=%f x=%f y=%f z=%f timeStamp:%f, UpTime:%f", totalAccelerationInXY, userAcceleration.x, userAcceleration.y, userAcceleration.z, deviceMotion.timestamp, [[NSProcessInfo processInfo] systemUptime]);
x2 = x1;
y2 = y1;
z2 = z1;
}
}
}
}
I know its old but i am posting for others who might be interested.
This Shake detection code can be also be used without ViewController or when the app is in the background (just by using the coremotion)
import CoreMotion
private var centralManager : CBCentralManager!
#IBOutlet weak var shakeLabel: UILabel!
let manager = CMMotionManager()
override func viewDidLoad() {
super.viewDidLoad()
var xInPositiveDirection = 0.0
var xInNegativeDirection = 0.0
var shakeCount = 0
var tempVariable = 0
manager.deviceMotionUpdateInterval = 0.02
manager.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: {
(data, error) in
if data!.userAcceleration.x > 1.0 || data!.userAcceleration.x < -1.0 {
if data!.userAcceleration.x > 1.0 {
xInPositiveDirection = data!.userAcceleration.x
}
if data!.userAcceleration.x < -1.0 {
xInNegativeDirection = data!.userAcceleration.x
}
if xInPositiveDirection != 0.0 && xInNegativeDirection != 0.0 {
shakeCount = shakeCount + 1
xInPositiveDirection = 0.0
xInNegativeDirection = 0.0
}
if shakeCount > 5 {
tempVariable = tempVariable + 1
self.shakeLabel.text = "Shaken! \(tempVariable)"
shakeCount = 0
}
}
})

Plot Array as Graph in ImageView

How can I plot an array to an imageview as a graph?
I've been testing this in Playground and it works, but how can plot this as an imageview in an actual project?
let sineArraySize = 64
let frequency1 = 4.0
let phase1 = 0.0
let amplitude1 = 2.0
let sineWave = (0..<sineArraySize).map {
amplitude1 * sin(2.0 * M_PI / Double(sineArraySize) * Double($0) * frequency1 + phase1)
}
func plotArrayInPlayground<T>(arrayToPlot:Array<T>, title:String) {
for currentValue in arrayToPlot {
XCPCaptureValue(title, currentValue)
}
}
plotArrayInPlayground(sineWave, "Sine wave 1")
One way you could do this:
// this function creates a plot of an array of doubles where it scales to the provided width and the x-axis is on half height
func plotArray(arr: [Double], width: Double, height: Double) -> NSImage {
if arr.isEmpty { return NSImage() }
let xAxisHeight = height / 2
let increment = width / Double(arr.count)
let image = NSImage(size: NSSize(width: width, height: height))
image.lockFocus()
// set background color
NSColor.whiteColor().set()
NSRectFill(NSRect(x: 0, y: 0, width: width, height: height))
let path = NSBezierPath()
// line width of plot
path.lineWidth = 5
path.moveToPoint(NSPoint(x: 0, y: arr[0] * increment + xAxisHeight))
var i = increment
for value in dropFirst(sineWave) {
path.lineToPoint(NSPoint(x: i, y: value * increment + xAxisHeight))
i += increment
}
// set plot color
NSColor.blueColor().set()
path.stroke()
image.unlockFocus()
return image
}
var imageView = NSImageView()
imageView.image = plotArray(sineWave, 500, 200)
// have fun