I tried a test-project. It worked but the method I used, put programmatically created labels over old existing labels. When the length of a string array is lower than the old one, it shows unnecessary old labels due to addSubview method.
How can I handle this problem?
import UIKit
extension UIView {
func pushTransition(duration:CFTimeInterval) {
let animation:CATransition = CATransition()
animation.timingFunction = CAMediaTimingFunction(name:
kCAMediaTimingFunctionEaseInEaseOut)
animation.type = kCATransitionPush
animation.subtype = kCATransitionFromBottom
animation.duration = duration
self.layer.addAnimation(animation, forKey: kCATransitionPush)
}
}
class ViewController: UIViewController {
var current:Float = 125.24
var discount:Float = 1.212342748
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func doAction(sender: AnyObject) {
let currentstr = String(format: "₺%.2f", self.current)
let length = currentstr.characters.count
var strarray = Array(currentstr.characters)
strarray[length-3] = ","
print(strarray)
self.current = self.current-self.discount
let newcurrent = String(format: "₺%.2f", self.current)
let newcurrentlength = newcurrent.characters.count
var newcurrentarray = Array(newcurrent.characters)
newcurrentarray[newcurrentlength-3] = ","
print(newcurrentarray)
var labels = [UILabel]()
print(labels)
if (length == newcurrentlength) {
for i in 1 ..< length+1 {
labels.append(UILabel(frame: CGRectMake((15*CGFloat(i)), 100, 20, 20)))
if (strarray[i-1] == newcurrentarray[i-1]){
print("SAME")
labels[i-1].text = String(newcurrentarray[i-1])
labels[i-1].textAlignment = NSTextAlignment.Center
labels[i-1].backgroundColor = UIColor.redColor()
self.view.addSubview(labels[i-1])
} else {
print("CHANGED")
labels[i-1].pushTransition(0.4)
labels[i-1].text = String(newcurrentarray[i-1])
labels[i-1].textAlignment = NSTextAlignment.Center
labels[i-1].backgroundColor = UIColor.redColor()
self.view.addSubview(labels[i-1])
}
}
} else {
for i in 1..<newcurrentlength+1 {
labels.append(UILabel(frame: CGRectMake((15*CGFloat(i)), 100, 20, 20)))
if (strarray[i-1] == newcurrentarray[i-1]){
print("SAME")
labels[i-1].text = String(newcurrentarray[i-1])
labels[i-1].textAlignment = NSTextAlignment.Center
labels[i-1].backgroundColor = UIColor.redColor()
self.view.addSubview(labels[i-1])
} else {
print("CHANGED")
labels[i-1].pushTransition(0.4)
labels[i-1].text = String(newcurrentarray[i-1])
labels[i-1].textAlignment = NSTextAlignment.Center
labels[i-1].backgroundColor = UIColor.redColor()
self.view.addSubview(labels[i-1])
}
}
}
}
}
EDIT
I put label array out of action section and it's fixed.
var labels = [UILabel]()
However, the transition between 100,00 and 99,99 there is a problem with the last child of label array. It still shows last digit like 99,990
I am sending keyboard key press and key release events, which works for all keyboard keys.
But modifier keys works only when the key associated with modifier key is sent from application, and not from real hardware. That is if I send
Shift and 'a' from application, it prints 'A' (capital A, which is what is expected).
But if I send 'shift' key down event from application, and enter 'a' from physical keyboard, it prints 'a' (the shift key doesn't seem to be working across different devices). The same applies for other modifier keys such as cmd, alt, and fn keys!.
Is there a way to send modifier keys to system, so that I can emulate modifier keys from my application?.
Specifically, I would like to activate modifier key from application, and enter the combination key from physical keyboard.
Here is the code I use to send key press and release events.
- (void)setADBKey:(uint32)key value:(int)value
{
if (!eventSource)
{
eventSource = CGEventSourceCreate(kCGEventSourceStatePrivate);
}
CGEventRef event = CGEventCreateKeyboardEvent(eventSource, key, value!=0);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
}
I have also tried creating and sending a system event, through the following code
struct
{
CGKeyCode keyCode;
int flag;
int cgEventFlag;
} modifiers[] = {
{ 56, NX_DEVICELSHIFTKEYMASK, kCGEventFlagMaskShift },
{ 60, NX_DEVICERSHIFTKEYMASK, kCGEventFlagMaskShift },
{ 59, NX_DEVICELCTLKEYMASK, kCGEventFlagMaskControl },
{ 58, NX_DEVICELALTKEYMASK, kCGEventFlagMaskAlternate },
{ 61, NX_DEVICERALTKEYMASK, kCGEventFlagMaskAlternate },
{ 55, NX_DEVICELCMDKEYMASK, kCGEventFlagMaskCommand },
{ 54, NX_DEVICERCMDKEYMASK, kCGEventFlagMaskCommand }
};
- (void)setAdbKey:(uint32)adbkey value:(int)value repeat:(BOOL)repeat
{
//int adbkey = def_usb_2_adb_keymap[hidkey];
int modifier = 0;
for(int i=0; i< ARR_SIZE(modifiers); i++)
{
if (adbkey == modifiers[i].keyCode)
{
modifier = modifiers[i].cgEventFlag;
break;
}
}
if (value)
{
flags |= modifier;
}
else
{
flags &= ~modifier;
}
CGEventRef event = CGEventCreateKeyboardEvent(eventSource, adbkey, value!=0);
if (repeat)
{
CGEventSetIntegerValueField(event, kCGKeyboardEventAutorepeat, (int64_t)1);
}
// don't apply modifier flags to a modifier
if (!modifier)
{
CGEventSetFlags(event, flags);
}
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
}
Both methods work when modifier key and combination key are sent from application, but not when modifier key alone is set from application.
All you have to do is create an event tap and set the mask.
Sample:
#interface AppDelegate ()
#property (assign) CFMachPortRef myEventTap;
#property (assign) CFRunLoopSourceRef myRunLoopSource;
#end
#implementation AppDelegate
CGEventRef MyEventTapCallBack(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
CGEventSetFlags(event, kCGEventFlagMaskShift);
return event;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.myEventTap = CGEventTapCreate(kCGHIDEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp) | CGEventMaskBit(kCGEventFlagsChanged),
MyEventTapCallBack,
(__bridge void *)self);
if (self.myEventTap) {
self.myRunLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, self.myEventTap, 0);
if (self.myRunLoopSource)
CFRunLoopAddSource(CFRunLoopGetMain(), self.myRunLoopSource, kCFRunLoopCommonModes);
}
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
if (self.myRunLoopSource) {
CFRunLoopSourceInvalidate(self.myRunLoopSource);
CFRelease(self.myRunLoopSource);
}
if (self.myEventTap)
CFRelease(self.myEventTap);
}
#end
This is my appDelegate and how I got it working.
import Cocoa
import CoreGraphics
import Foundation
var shift = false;
var cntrl = false;
var option = false;
var command = false;
func myCGEventCallback(proxy: CGEventTapProxy, type: CGEventType, event: CGEvent, refcon: UnsafeMutableRawPointer?) -> Unmanaged<CGEvent>? {
var mask: CGEventFlags = []
if(shift) {
mask.insert(CGEventFlags.maskShift)
}
if(cntrl) {
mask.insert(CGEventFlags.maskControl)
}
if(option) {
mask.insert(CGEventFlags.maskAlternate)
}
if(command) {
mask.insert(CGEventFlags.maskCommand)
}
if(mask.rawValue != 0) {
event.flags = mask;
}
return Unmanaged.passRetained(event)
}
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
let mask: CGEventMask = 1 << CGEventType.keyDown.rawValue
let eventTap:CFMachPort = CGEvent.tapCreate(tap: .cghidEventTap, place: .headInsertEventTap, options: .defaultTap, eventsOfInterest: mask, callback: myCGEventCallback, userInfo: nil)!
let runLoopSource:CFRunLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, CFRunLoopMode.commonModes);
CGEvent.tapEnable(tap: eventTap, enable: true);
CFRunLoopRun();
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
public func SetShift() {
shift = !shift;
}
public func SetCtrl() {
cntrl = !cntrl;
}
public func SetCommand() {
command = !command;
}
public func SetOption() {
option = !option;
}
}
I have the following Objective-C method:
- (void)addPolygonToMap {
NSInteger numberOfPoints = [self.coordinates count];
if (numberOfPoints > 4) {
CLLocationCoordinate2D points[numberOfPoints];
for (NSInteger i = 0; i < numberOfPoints; i++) {
points[i] = [self.coordinates[i] MKCoordinateValue];
}
self.polygon = [MKPolygon polygonWithCoordinates:points count:numberOfPoints];
[self.mapView addOverlay: self.polygon];
}
self.isDrawingPolygon = NO;
[self.drawPolygonButton setTitle:#"draw" forState:UIControlStateNormal];
self.canvasView.image = nil;
[self.canvasView removeFromSuperview];
}
My attempt at converting it to Swift:
func addPolygonToMap() {
var numberOfPoints: NSInteger = self.coordinates.count
if (numberOfPoints > 4) {
var points: [CLLocationCoordinate2D] = []
var coordsPointer = UnsafeMutablePointer<CLLocationCoordinate2D>.alloc(numberOfPoints)
for i in 0..<numberOfPoints {
points.append(coordsPointer[i])
}
self.polygon = MKPolygon(coordinates: &points, count: numberOfPoints)
self.mapView.addOverlay(self.polygon)
coordsPointer.dealloc(numberOfPoints)
}
self.isDrawingPolygon = false
self.drawPolygonButton.setTitle("Draw", forState: .Normal)
self.canvasView.image = nil
self.canvasView.removeFromSuperview()
}
Finally, when the delegate method is called it's not actually adding the overlay to the mapView. I can't see anything.
I'm assuming it's my self.addPolytonToMap() method, but I'm not 100% sure. The whole scenario works fine in my Objective-C project.
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {
if (overlay is MKPolygon) {
var overlayPathView = MKPolygonRenderer(overlay: overlay)
overlayPathView.fillColor = UIColor.cyanColor().colorWithAlphaComponent(0.2)
overlayPathView.strokeColor = UIColor.cyanColor().colorWithAlphaComponent(0.2)
overlayPathView.lineWidth = 5
return overlayPathView
} else if (overlay is MKPolyline) {
var overlayPathView = MKPolylineRenderer(overlay: overlay)
overlayPathView.strokeColor = UIColor.blueColor().colorWithAlphaComponent(0.7)
overlayPathView.lineWidth = 5
return overlayPathView
}
return nil
}
UPDATE:
I just noticed that in my Objective-C version, the points[i].latitude are coming through okay, however when I do the following I get a strange output:
println(coordsPointer[i].latitude)
Output:
1.63041663127611e-321
1.64523860065135e-321
1.65511991356818e-321
1.68970450877706e-321
1.7045264781523e-321
1.72922976044436e-321
This would explain why I don't see the overlay, however my experience with UnsafeMutablePointer<> is limited.
Fixed by modifying the addPolygonToMap() method:
func addPolygonToMap() {
var numberOfPoints: NSInteger = self.coordinates.count
if (numberOfPoints > 4) {
var points: [CLLocationCoordinate2D] = []
for i in 0..<numberOfPoints {
points.insert(self.coordinates[i].MKCoordinateValue, atIndex: i)
}
self.polygon = MKPolygon(coordinates: &points, count: numberOfPoints)
self.mapView.addOverlay(self.polygon)
}
self.isDrawingPolygon = false
self.drawPolygonButton.setTitle("Draw", forState: .Normal)
self.canvasView.image = nil
self.canvasView.removeFromSuperview()
}
Thanks to #Volker for the help.
I have separate landscape and portrait views in iOS7 using the code below:
-(void)didRotateFromInterfaceOrientation: (UIInterfaceOrientation)fromInterfaceOrientation {
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
CGRect currentBounds=self.view.bounds;
if (iPadInt==0) {
if (self.interfaceOrientation==UIInterfaceOrientationLandscapeRight) {
self.view=self.landscapeQuestionView;
self.view.transform=CGAffineTransformMakeRotation((kDeg2Rad)*(90));
} else if (self.interfaceOrientation==UIInterfaceOrientationLandscapeLeft) {
self.view=self.landscapeQuestionView;
self.view.transform=CGAffineTransformMakeRotation((kDeg2Rad)*(-90));
} else if (self.interfaceOrientation==UIInterfaceOrientationPortrait) {
self.view=self.portraitQuestionView;
self.view.transform=CGAffineTransformMakeRotation(0);
} else if (self.interfaceOrientation==UIInterfaceOrientationPortraitUpsideDown) {
self.view=self.portraitQuestionView;
self.view.transform=CGAffineTransformMakeRotation((kDeg2Rad)*(180));
} self.view.bounds=currentBounds;
} else if (iPadInt==1) {
if (self.interfaceOrientation==UIInterfaceOrientationLandscapeRight) {
self.view=self.iPadLandscapeQuestionView;
self.view.transform=CGAffineTransformMakeRotation((kDeg2Rad)*(90));
rotationInt=90;
} else if (self.interfaceOrientation==UIInterfaceOrientationLandscapeLeft) {
self.view=self.iPadLandscapeQuestionView;
self.view.transform=CGAffineTransformMakeRotation((kDeg2Rad)*(-90));
rotationInt=90;
} else if (self.interfaceOrientation==UIInterfaceOrientationPortrait) {
self.view=self.iPadPortraitQuestionView;
self.view.transform=CGAffineTransformMakeRotation(0);
rotationInt=0;
} else if (self.interfaceOrientation==UIInterfaceOrientationPortraitUpsideDown) {
self.view=self.iPadPortraitQuestionView;
self.view.transform=CGAffineTransformMakeRotation((kDeg2Rad)*(180));
rotationInt=0;
} self.view.bounds=currentBounds;
}
}
I know I should use the viewWillTransitionToSize method in iOS8, but I can't figure out how to get these different views in that method. Thanks in advance for any help.
There is a topic here: Rotation methods deprecated, equivalent of 'didRotateFromInterfaceOrientation'?
I think in your situation you can use viewWillTransitionToSize: like this:
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
//get orientation
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
//check orientation
if (orientation==UIInterfaceOrientationPortrait)
{
NSLog(#"portrait");
}
else if(orientation==UIInterfaceOrientationPortraitUpsideDown)
{
NSLog(#"upside-down");
}
else if(orientation==UIInterfaceOrientationLandscapeRight)
{
NSLog(#"landscape right");
}
else if(orientation==UIInterfaceOrientationLandscapeLeft)
{
NSLog(#"landscape left");
}
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
}];
}
in iOS8 the dimension returned is 0,0
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
This was working on iOS7, so how to know the supported video dimension, as i need to know the video aspect ratio
You need to wait for the AVCaptureInputPortFormatDescriptionDidChangeNotification
- (void)avCaptureInputPortFormatDescriptionDidChangeNotification:(NSNotification *)notification {
AVCaptureInput *input = [self.recorder.captureSession.inputs objectAtIndex:0];
AVCaptureInputPort *port = [input.ports objectAtIndex:0];
CMFormatDescriptionRef formatDescription = port.formatDescription;
if (formatDescription) {
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
if ((dimensions.width == 0) || (dimensions.height == 0)) {
return;
}
CGFloat aspect = (CGFloat)dimensions.width / (CGFloat)dimensions.height;
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1) {
// since iOS8 the aspect ratio is inverted
// remove this check if iOS7 will not be supported
aspect = 1.f / aspect;
}
}
}
Provided you're tracking the device being used, you can access the current format from activeFormat: https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVCaptureDevice_Class/index.html#//apple_ref/occ/instp/AVCaptureDevice/activeFormat
I recently ran into this particular issue, here's the Swift 5 version for those who need it too:
import Foundation
import AVFoundation
class MySessionManager: NSObject {
static let notificationName = "AVCaptureInputPortFormatDescriptionDidChangeNotification"
let session: AVCaptureSession
var videoCaptureDimensions: CMVideoDimensions?
init(session: AVCaptureSession) {
self.session = session
let notificationName = NSNotification.Name()
NotificationCenter.default.addObserver(
self,
selector: #selector(formatDescription(didChange:)),
name: .init(Self.notificationName),
object: nil
)
}
deinit { NotificationCenter.default.removeObserver(self) }
#objc func formatDescription(didChange notification: NSNotification) {
guard
let input = session.inputs.first,
let port = input.ports.first,
let formatDesc = port.formatDescription
else { return }
var dimensions = CMVideoFormatDescriptionGetDimensions(formatDesc)
// ... perform any necessary dim adjustments ...
videoCaptureDimensions = dimensions
}
}