Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
Material
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Dmitriy Stepanets
Material
Commits
d3b4ccc1
Commit
d3b4ccc1
authored
Dec 15, 2015
by
Daniel Dahan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
decoupling views for CaptureView
parent
61a63660
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
672 additions
and
622 deletions
+672
-622
Examples/Programmatic/CaptureView/CaptureView/ViewController.swift
+9
-298
Examples/Storyboards/MaterialButton/MaterialButton/Base.lproj/Main.storyboard
+2
-6
MaterialKit.xcodeproj/project.pbxproj
+4
-0
Sources/CameraView.swift
+331
-0
Sources/CapturePreviewView.swift
+11
-200
Sources/CaptureSession.swift
+42
-38
Sources/CaptureView.swift
+227
-80
Sources/MaterialAnimation.swift
+46
-0
No files found.
Examples/Programmatic/CaptureView/CaptureView/ViewController.swift
View file @
d3b4ccc1
...
...
@@ -25,32 +25,20 @@ enum CaptureMode {
case
Video
}
class
ViewController
:
UIViewController
,
CapturePreviewViewDelegate
,
CaptureSessionDelegate
{
private
lazy
var
navigationBarView
:
NavigationBarView
=
NavigationBarView
()
private
lazy
var
captureView
:
CaptureView
=
CaptureView
()
private
lazy
var
cameraButton
:
FlatButton
=
FlatButton
()
private
lazy
var
captureButton
:
FabButton
=
FabButton
()
private
lazy
var
videoButton
:
FlatButton
=
FlatButton
()
private
lazy
var
switchCameraButton
:
FlatButton
=
FlatButton
()
private
lazy
var
flashButton
:
FlatButton
=
FlatButton
()
private
lazy
var
closeButton
:
FlatButton
=
FlatButton
()
private
lazy
var
captureMode
:
CaptureMode
=
.
Video
private
var
timer
:
NSTimer
?
class
ViewController
:
UIViewController
,
CaptureViewDelegate
,
CaptureSessionDelegate
{
private
lazy
var
cameraView
:
CameraView
=
CameraView
()
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
prepareView
()
prepareCaptureView
()
prepareNavigationBarView
()
prepareCaptureButton
()
prepareCameraButton
()
prepareVideoButton
()
prepareCloseButton
()
prepareSwitchCameraButton
()
prepareFlashButton
()
prepareCameraView
()
}
private
func
prepareCameraView
()
{
cameraView
.
translatesAutoresizingMaskIntoConstraints
=
false
view
.
addSubview
(
cameraView
)
MaterialLayout
.
alignToParent
(
view
,
child
:
cameraView
)
}
/**
...
...
@@ -61,246 +49,6 @@ class ViewController: UIViewController, CapturePreviewViewDelegate, CaptureSessi
}
/**
:name: prepareNavigationBarView
*/
private
func
prepareNavigationBarView
()
{
navigationBarView
.
backgroundColor
=
MaterialColor
.
black
.
colorWithAlphaComponent
(
0.3
)
navigationBarView
.
shadowDepth
=
.
None
navigationBarView
.
statusBarStyle
=
.
LightContent
// Title label.
let
titleLabel
:
UILabel
=
UILabel
()
titleLabel
.
text
=
"00:00:00"
titleLabel
.
textAlignment
=
.
Left
titleLabel
.
textColor
=
MaterialColor
.
white
titleLabel
.
font
=
RobotoFont
.
regularWithSize
(
20
)
navigationBarView
.
titleLabel
=
titleLabel
navigationBarView
.
titleLabelInsetsRef
.
left
=
64
// Detail label
let
detailLabel
:
UILabel
=
UILabel
()
detailLabel
.
text
=
"Stopped"
detailLabel
.
textAlignment
=
.
Left
detailLabel
.
textColor
=
MaterialColor
.
white
detailLabel
.
font
=
RobotoFont
.
regularWithSize
(
12
)
navigationBarView
.
detailLabel
=
detailLabel
navigationBarView
.
detailLabelInsetsRef
.
left
=
64
view
.
addSubview
(
navigationBarView
)
navigationBarView
.
leftButtons
=
[
closeButton
]
navigationBarView
.
rightButtons
=
[
switchCameraButton
,
flashButton
]
}
/**
:name: prepareCaptureButton
*/
private
func
prepareCaptureButton
()
{
captureButton
.
pulseColor
=
MaterialColor
.
white
captureButton
.
pulseFill
=
true
captureButton
.
backgroundColor
=
MaterialColor
.
red
.
darken1
.
colorWithAlphaComponent
(
0.3
)
captureButton
.
borderWidth
=
.
Border2
captureButton
.
borderColor
=
MaterialColor
.
white
captureButton
.
shadowDepth
=
.
None
captureButton
.
addTarget
(
self
,
action
:
"handleCaptureButton:"
,
forControlEvents
:
.
TouchUpInside
)
view
.
addSubview
(
captureButton
)
captureButton
.
translatesAutoresizingMaskIntoConstraints
=
false
MaterialLayout
.
alignFromBottomRight
(
view
,
child
:
captureButton
,
bottom
:
24
,
right
:
(
view
.
bounds
.
width
-
72
)
/
2
)
MaterialLayout
.
size
(
view
,
child
:
captureButton
,
width
:
72
,
height
:
72
)
}
/**
:name: prepareCameraButton
*/
private
func
prepareCameraButton
()
{
let
img4
:
UIImage
?
=
UIImage
(
named
:
"ic_photo_camera_white_36pt"
)
cameraButton
.
pulseColor
=
nil
cameraButton
.
setImage
(
img4
,
forState
:
.
Normal
)
cameraButton
.
setImage
(
img4
,
forState
:
.
Highlighted
)
cameraButton
.
addTarget
(
self
,
action
:
"handleCameraButton:"
,
forControlEvents
:
.
TouchUpInside
)
view
.
addSubview
(
cameraButton
)
cameraButton
.
translatesAutoresizingMaskIntoConstraints
=
false
MaterialLayout
.
alignFromBottomLeft
(
view
,
child
:
cameraButton
,
bottom
:
24
,
left
:
24
)
}
/**
:name: prepareVideoButton
*/
private
func
prepareVideoButton
()
{
let
img5
:
UIImage
?
=
UIImage
(
named
:
"ic_videocam_white_36pt"
)
videoButton
.
pulseColor
=
nil
videoButton
.
setImage
(
img5
,
forState
:
.
Normal
)
videoButton
.
setImage
(
img5
,
forState
:
.
Highlighted
)
videoButton
.
addTarget
(
self
,
action
:
"handleVideoButton:"
,
forControlEvents
:
.
TouchUpInside
)
view
.
addSubview
(
videoButton
)
videoButton
.
translatesAutoresizingMaskIntoConstraints
=
false
MaterialLayout
.
alignFromBottomRight
(
view
,
child
:
videoButton
,
bottom
:
24
,
right
:
24
)
}
/**
:name: prepareCloseButton
*/
private
func
prepareCloseButton
()
{
let
img
:
UIImage
?
=
UIImage
(
named
:
"ic_close_white"
)
closeButton
.
pulseColor
=
MaterialColor
.
white
closeButton
.
pulseFill
=
true
closeButton
.
setImage
(
img
,
forState
:
.
Normal
)
closeButton
.
setImage
(
img
,
forState
:
.
Highlighted
)
}
/**
:name: prepareSwitchCameraButton
*/
private
func
prepareSwitchCameraButton
()
{
let
img
:
UIImage
?
=
UIImage
(
named
:
"ic_camera_front_white"
)
switchCameraButton
.
pulseColor
=
MaterialColor
.
white
switchCameraButton
.
pulseFill
=
true
switchCameraButton
.
setImage
(
img
,
forState
:
.
Normal
)
switchCameraButton
.
setImage
(
img
,
forState
:
.
Highlighted
)
switchCameraButton
.
addTarget
(
self
,
action
:
"handleSwitchCameraButton:"
,
forControlEvents
:
.
TouchUpInside
)
}
/**
:name: prepareFlashButton
*/
private
func
prepareFlashButton
()
{
captureView
.
captureSession
.
flashMode
=
.
Auto
let
img
:
UIImage
?
=
UIImage
(
named
:
"ic_flash_auto_white"
)
flashButton
.
pulseColor
=
MaterialColor
.
white
flashButton
.
pulseFill
=
true
flashButton
.
setImage
(
img
,
forState
:
.
Normal
)
flashButton
.
setImage
(
img
,
forState
:
.
Highlighted
)
flashButton
.
addTarget
(
self
,
action
:
"handleFlashButton:"
,
forControlEvents
:
.
TouchUpInside
)
}
/**
:name: prepareCaptureView
*/
private
func
prepareCaptureView
()
{
captureView
.
captureSession
.
delegate
=
self
captureView
.
captureButton
=
captureButton
captureView
.
flashButton
=
flashButton
captureView
.
switchCamerasButton
=
switchCameraButton
view
.
addSubview
(
captureView
)
captureView
.
translatesAutoresizingMaskIntoConstraints
=
false
MaterialLayout
.
alignToParent
(
view
,
child
:
captureView
)
}
/**
:name: handleCaptureButton
*/
internal
func
handleCaptureButton
(
button
:
UIButton
)
{
if
.
Photo
==
captureMode
{
captureView
.
captureSession
.
captureStillImage
()
}
else
if
.
Video
==
captureMode
{
if
captureView
.
captureSession
.
isRecording
{
captureView
.
captureSession
.
stopRecording
()
stopTimer
()
}
else
{
captureView
.
captureSession
.
startRecording
()
startTimer
()
}
}
}
/**
:name: handleSwitchCameraButton
*/
internal
func
handleSwitchCameraButton
(
button
:
UIButton
)
{
var
img
:
UIImage
?
if
.
Back
==
captureView
.
captureSession
.
cameraPosition
{
img
=
UIImage
(
named
:
"ic_camera_rear_white"
)
captureView
.
captureSession
.
switchCameras
()
}
else
if
.
Front
==
captureView
.
captureSession
.
cameraPosition
{
img
=
UIImage
(
named
:
"ic_camera_front_white"
)
captureView
.
captureSession
.
switchCameras
()
}
switchCameraButton
.
setImage
(
img
,
forState
:
.
Normal
)
switchCameraButton
.
setImage
(
img
,
forState
:
.
Highlighted
)
}
/**
:name: handleFlashButton
*/
internal
func
handleFlashButton
(
button
:
UIButton
)
{
if
.
Back
==
captureView
.
captureSession
.
cameraPosition
{
var
img
:
UIImage
?
switch
captureView
.
captureSession
.
flashMode
{
case
.
Off
:
img
=
UIImage
(
named
:
"ic_flash_on_white"
)
captureView
.
captureSession
.
flashMode
=
.
On
case
.
On
:
img
=
UIImage
(
named
:
"ic_flash_auto_white"
)
captureView
.
captureSession
.
flashMode
=
.
Auto
case
.
Auto
:
img
=
UIImage
(
named
:
"ic_flash_off_white"
)
captureView
.
captureSession
.
flashMode
=
.
Off
}
flashButton
.
setImage
(
img
,
forState
:
.
Normal
)
flashButton
.
setImage
(
img
,
forState
:
.
Highlighted
)
}
}
/**
:name: handleCameraButton
*/
func
handleCameraButton
(
button
:
UIButton
)
{
captureButton
.
backgroundColor
=
MaterialColor
.
blue
.
darken1
.
colorWithAlphaComponent
(
0.3
)
captureMode
=
.
Photo
navigationBarView
.
titleLabel
!.
text
=
""
navigationBarView
.
detailLabel
!.
text
=
""
}
/**
:name: handleVideoButton
*/
func
handleVideoButton
(
button
:
UIButton
)
{
captureButton
.
backgroundColor
=
MaterialColor
.
red
.
darken1
.
colorWithAlphaComponent
(
0.3
)
captureMode
=
.
Video
navigationBarView
.
titleLabel
!.
text
=
"00:00:00"
navigationBarView
.
detailLabel
!.
text
=
"Stopped"
}
/**
:name: captureSessionFailedWithError
*/
func
captureSessionFailedWithError
(
capture
:
CaptureSession
,
error
:
NSError
)
{
print
(
error
)
}
/**
:name: captureSessionWillSwitchCameras
*/
func
captureSessionWillSwitchCameras
(
capture
:
CaptureSession
,
position
:
AVCaptureDevicePosition
)
{
if
.
Back
==
position
{
let
img
:
UIImage
?
=
UIImage
(
named
:
"ic_flash_off_white"
)
captureView
.
captureSession
.
flashMode
=
.
Off
flashButton
.
setImage
(
img
,
forState
:
.
Normal
)
flashButton
.
setImage
(
img
,
forState
:
.
Highlighted
)
}
}
/**
:name: captureSessionDidSwitchCameras
*/
func
captureSessionDidSwitchCameras
(
capture
:
CaptureSession
,
position
:
AVCaptureDevicePosition
)
{
if
.
Back
==
position
{
let
img
:
UIImage
?
=
UIImage
(
named
:
"ic_flash_auto_white"
)
captureView
.
captureSession
.
flashMode
=
.
Auto
flashButton
.
setImage
(
img
,
forState
:
.
Normal
)
flashButton
.
setImage
(
img
,
forState
:
.
Highlighted
)
}
}
/**
:name: captureStillImageAsynchronously
*/
func
captureStillImageAsynchronously
(
capture
:
CaptureSession
,
image
:
UIImage
)
{
...
...
@@ -327,41 +75,4 @@ class ViewController: UIViewController, CapturePreviewViewDelegate, CaptureSessi
func
captureDidFinishRecordingToOutputFileAtURL
(
capture
:
CaptureSession
,
captureOutput
:
AVCaptureFileOutput
,
outputFileURL
:
NSURL
,
fromConnections
connections
:
[
AnyObject
],
error
:
NSError
!
)
{
print
(
"Capture Stopped Recording
\(
outputFileURL
)
"
)
}
/**
:name: startTimer
*/
func
startTimer
()
{
timer
?
.
invalidate
()
timer
=
NSTimer
(
timeInterval
:
0.5
,
target
:
self
,
selector
:
"updateTimer"
,
userInfo
:
nil
,
repeats
:
true
)
NSRunLoop
.
mainRunLoop
()
.
addTimer
(
timer
!
,
forMode
:
NSRunLoopCommonModes
)
navigationBarView
.
detailLabel
!.
textColor
=
MaterialColor
.
red
.
accent1
captureButton
.
backgroundColor
=
MaterialColor
.
red
.
darken4
.
colorWithAlphaComponent
(
0.3
)
}
/**
:name: updateTimer
*/
func
updateTimer
()
{
let
duration
:
CMTime
=
captureView
.
captureSession
.
recordedDuration
let
time
:
Double
=
CMTimeGetSeconds
(
duration
)
let
hours
:
Int
=
Int
(
time
/
3600
)
let
minutes
:
Int
=
Int
((
time
/
60
)
%
60
)
let
seconds
:
Int
=
Int
(
time
%
60
)
navigationBarView
.
titleLabel
!.
text
=
String
(
format
:
"%02i:%02i:%02i"
,
arguments
:
[
hours
,
minutes
,
seconds
])
navigationBarView
.
detailLabel
!.
text
=
"Recording"
}
/**
:name: stopTimer
*/
func
stopTimer
()
{
timer
?
.
invalidate
()
timer
=
nil
navigationBarView
.
titleLabel
!.
text
=
"00:00:00"
navigationBarView
.
detailLabel
!.
text
=
"Stopped"
navigationBarView
.
detailLabel
!.
textColor
=
MaterialColor
.
white
captureButton
.
backgroundColor
=
MaterialColor
.
red
.
darken1
.
colorWithAlphaComponent
(
0.3
)
}
}
Examples/Storyboards/MaterialButton/MaterialButton/Base.lproj/Main.storyboard
View file @
d3b4ccc1
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document
type=
"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB"
version=
"3.0"
toolsVersion=
"9
060
"
systemVersion=
"15B42"
targetRuntime=
"iOS.CocoaTouch"
propertyAccessControl=
"none"
useAutolayout=
"YES"
useTraitCollections=
"YES"
initialViewController=
"BYZ-38-t0r"
>
<document
type=
"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB"
version=
"3.0"
toolsVersion=
"9
531
"
systemVersion=
"15B42"
targetRuntime=
"iOS.CocoaTouch"
propertyAccessControl=
"none"
useAutolayout=
"YES"
useTraitCollections=
"YES"
initialViewController=
"BYZ-38-t0r"
>
<dependencies>
<deployment
identifier=
"iOS"
/>
<plugIn
identifier=
"com.apple.InterfaceBuilder.IBCocoaTouchPlugin"
version=
"9
051
"
/>
<plugIn
identifier=
"com.apple.InterfaceBuilder.IBCocoaTouchPlugin"
version=
"9
529
"
/>
</dependencies>
<scenes>
<!--View Controller-->
...
...
@@ -19,21 +19,17 @@
<subviews>
<button
opaque=
"NO"
contentMode=
"scaleToFill"
fixedFrame=
"YES"
contentHorizontalAlignment=
"center"
contentVerticalAlignment=
"center"
buttonType=
"roundedRect"
lineBreakMode=
"middleTruncation"
translatesAutoresizingMaskIntoConstraints=
"NO"
id=
"g8F-Xx-oIC"
customClass=
"RaisedButton"
customModule=
"MaterialKit"
>
<rect
key=
"frame"
x=
"107"
y=
"207"
width=
"200"
height=
"65"
/>
<animations/>
<state
key=
"normal"
title=
"Button"
/>
</button>
<button
opaque=
"NO"
contentMode=
"scaleToFill"
fixedFrame=
"YES"
contentHorizontalAlignment=
"center"
contentVerticalAlignment=
"center"
buttonType=
"roundedRect"
lineBreakMode=
"middleTruncation"
translatesAutoresizingMaskIntoConstraints=
"NO"
id=
"KGx-lb-zep"
customClass=
"FlatButton"
customModule=
"MaterialKit"
>
<rect
key=
"frame"
x=
"107"
y=
"107"
width=
"200"
height=
"65"
/>
<animations/>
<state
key=
"normal"
title=
"Button"
/>
</button>
<button
opaque=
"NO"
contentMode=
"scaleToFill"
fixedFrame=
"YES"
contentHorizontalAlignment=
"center"
contentVerticalAlignment=
"center"
buttonType=
"roundedRect"
lineBreakMode=
"middleTruncation"
translatesAutoresizingMaskIntoConstraints=
"NO"
id=
"ZEH-7f-aTd"
customClass=
"FabButton"
customModule=
"MaterialKit"
>
<rect
key=
"frame"
x=
"175"
y=
"315"
width=
"64"
height=
"64"
/>
<animations/>
<color
key=
"backgroundColor"
red=
"1"
green=
"0.0"
blue=
"0.0"
alpha=
"1"
colorSpace=
"calibratedRGB"
/>
</button>
</subviews>
<animations/>
<color
key=
"backgroundColor"
white=
"1"
alpha=
"1"
colorSpace=
"custom"
customColorSpace=
"calibratedWhite"
/>
</view>
<simulatedScreenMetrics
key=
"simulatedDestinationMetrics"
type=
"retina47"
/>
...
...
MaterialKit.xcodeproj/project.pbxproj
View file @
d3b4ccc1
...
...
@@ -79,6 +79,7 @@
96D88C731C132ACC00B91418
/* MaterialAnimation.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96D88BFF1C1328D800B91418
/* MaterialAnimation.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
96D88C741C132ACC00B91418
/* MaterialBasicAnimation.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96D88C001C1328D800B91418
/* MaterialBasicAnimation.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
96D88C751C132AD500B91418
/* NavigationBarView.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96D88C151C1328D800B91418
/* NavigationBarView.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
96F367031C20B87D00DD91F4
/* CameraView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96F367021C20B87D00DD91F4
/* CameraView.swift */
;
};
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
...
...
@@ -136,6 +137,7 @@
96D88C1B1C1328D800B91418
/* Roboto-Thin.ttf */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
file
;
path
=
"Roboto-Thin.ttf"
;
sourceTree
=
"<group>"
;
};
96D88C1C1C1328D800B91418
/* RobotoFont.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
RobotoFont.swift
;
sourceTree
=
"<group>"
;
};
96D88C1D1C1328D800B91418
/* SideNavigationViewController.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
SideNavigationViewController.swift
;
sourceTree
=
"<group>"
;
};
96F367021C20B87D00DD91F4
/* CameraView.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
CameraView.swift
;
sourceTree
=
"<group>"
;
};
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
...
...
@@ -233,6 +235,7 @@
96D88C491C13292700B91418
/* Capture */
=
{
isa
=
PBXGroup
;
children
=
(
96F367021C20B87D00DD91F4
/* CameraView.swift */
,
96D88BF51C1328D800B91418
/* CaptureView.swift */
,
96D88BF71C1328D800B91418
/* CapturePreviewView.swift */
,
96D88BF81C1328D800B91418
/* CaptureSession.swift */
,
...
...
@@ -515,6 +518,7 @@
96D88C3F1C1328D800B91418
/* RaisedButton.swift in Sources */
,
96D88C3C1C1328D800B91418
/* MaterialTransitionAnimation.swift in Sources */
,
96D88C361C1328D800B91418
/* MaterialPulseView.swift in Sources */
,
96F367031C20B87D00DD91F4
/* CameraView.swift in Sources */
,
96D88C1E1C1328D800B91418
/* CaptureView.swift in Sources */
,
96D88C2D1C1328D800B91418
/* MaterialDepth.swift in Sources */
,
96D88C331C1328D800B91418
/* MaterialLabel.swift in Sources */
,
...
...
Sources/CameraView.swift
0 → 100644
View file @
d3b4ccc1
//
// Copyright (C) 2015 CosmicMind, Inc. <http://cosmicmind.io> and other CosmicMind contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import
UIKit
import
AVFoundation
public
enum
CaptureMode
{
case
Photo
case
Video
}
public
class
CameraView
:
CaptureView
,
CaptureViewDelegate
,
CaptureSessionDelegate
{
/**
:name: navigationBarView
*/
public
var
navigationBarView
:
NavigationBarView
=
NavigationBarView
(
frame
:
CGRectNull
)
/**
:name: captureMode
*/
public
private(set)
lazy
var
captureMode
:
CaptureMode
=
.
Video
/**
:name: prepareView
*/
public
override
func
prepareView
()
{
super
.
prepareView
()
prepareNavigationBarView
()
prepareCaptureButton
()
prepareCameraButton
()
prepareVideoButton
()
prepareCloseButton
()
prepareSwitchCameraButton
()
prepareFlashButton
()
}
public
func
captureViewDidUpdateRecordTimer
(
captureView
:
CaptureView
,
duration
:
CMTime
,
time
:
Double
,
hours
:
Int
,
minutes
:
Int
,
seconds
:
Int
)
{
MaterialAnimation
.
animationDisabled
{
self
.
navigationBarView
.
titleLabel
!.
text
=
String
(
format
:
"%02i:%02i:%02i"
,
arguments
:
[
hours
,
minutes
,
seconds
])
}
}
public
func
captureViewDidStopRecordTimer
(
captureView
:
CaptureView
,
duration
:
CMTime
,
time
:
Double
,
hours
:
Int
,
minutes
:
Int
,
seconds
:
Int
)
{
navigationBarView
.
titleLabel
!.
hidden
=
true
navigationBarView
.
detailLabel
!.
hidden
=
true
navigationBarView
.
detailLabel
!.
textColor
=
MaterialColor
.
white
}
/**
:name: captureSessionFailedWithError
*/
public
func
captureSessionFailedWithError
(
capture
:
CaptureSession
,
error
:
NSError
)
{
print
(
error
)
}
/**
:name: captureSessionWillSwitchCameras
*/
public
func
captureSessionWillSwitchCameras
(
capture
:
CaptureSession
,
position
:
AVCaptureDevicePosition
)
{
if
.
Back
==
position
{
let
img
:
UIImage
?
=
UIImage
(
named
:
"ic_flash_off_white"
)
captureSession
.
flashMode
=
.
Off
flashButton
!.
setImage
(
img
,
forState
:
.
Normal
)
flashButton
!.
setImage
(
img
,
forState
:
.
Highlighted
)
}
}
/**
:name: captureSessionDidSwitchCamerapublic s
*/
public
func
captureSessionDidSwitchCameras
(
capture
:
CaptureSession
,
position
:
AVCaptureDevicePosition
)
{
if
.
Back
==
position
{
let
img
:
UIImage
?
=
UIImage
(
named
:
"ic_flash_auto_white"
)
captureSession
.
flashMode
=
.
Auto
flashButton
!.
setImage
(
img
,
forState
:
.
Normal
)
flashButton
!.
setImage
(
img
,
forState
:
.
Highlighted
)
}
}
/**
:name: handleCameraButton
*/
internal
func
handleCameraButton
(
button
:
UIButton
)
{
captureButton
!.
backgroundColor
=
MaterialColor
.
blue
.
darken1
.
colorWithAlphaComponent
(
0.3
)
captureMode
=
.
Photo
}
/**
:name: handleVideoButton
*/
internal
func
handleVideoButton
(
button
:
UIButton
)
{
captureButton
!.
backgroundColor
=
MaterialColor
.
red
.
darken1
.
colorWithAlphaComponent
(
0.3
)
captureMode
=
.
Video
}
/**
:name: handleCaptureButton
*/
internal
func
handleCaptureButton
(
button
:
UIButton
)
{
if
.
Photo
==
captureMode
{
captureSession
.
captureStillImage
()
}
else
if
.
Video
==
captureMode
{
if
captureSession
.
isRecording
{
captureSession
.
stopRecording
()
stopTimer
()
cameraButton
!.
hidden
=
false
videoButton
!.
hidden
=
false
if
let
v
:
Array
<
UIButton
>
=
navigationBarView
.
leftButtons
{
for
x
in
v
{
x
.
hidden
=
false
}
}
if
let
v
:
Array
<
UIButton
>
=
navigationBarView
.
rightButtons
{
for
x
in
v
{
x
.
hidden
=
false
}
}
navigationBarView
.
backgroundColor
=
MaterialColor
.
black
.
colorWithAlphaComponent
(
0.3
)
}
else
{
previewView
.
layer
.
addAnimation
(
MaterialAnimation
.
transition
(
.
Fade
),
forKey
:
kCATransition
)
captureSession
.
startRecording
()
startTimer
()
cameraButton
!.
hidden
=
true
videoButton
!.
hidden
=
true
if
let
v
:
Array
<
UIButton
>
=
navigationBarView
.
leftButtons
{
for
x
in
v
{
x
.
hidden
=
true
}
}
if
let
v
:
Array
<
UIButton
>
=
navigationBarView
.
rightButtons
{
for
x
in
v
{
x
.
hidden
=
true
}
}
navigationBarView
.
backgroundColor
=
nil
}
}
}
/**
:name: handleSwitchCameraButton
*/
internal
func
handleSwitchCameraButton
(
button
:
UIButton
)
{
var
img
:
UIImage
?
previewView
.
layer
.
addAnimation
(
MaterialAnimation
.
transition
(
.
Fade
),
forKey
:
kCATransition
)
if
.
Back
==
captureSession
.
cameraPosition
{
img
=
UIImage
(
named
:
"ic_camera_rear_white"
)
captureSession
.
switchCameras
()
}
else
if
.
Front
==
captureSession
.
cameraPosition
{
img
=
UIImage
(
named
:
"ic_camera_front_white"
)
captureSession
.
switchCameras
()
}
switchCameraButton
!.
setImage
(
img
,
forState
:
.
Normal
)
switchCameraButton
!.
setImage
(
img
,
forState
:
.
Highlighted
)
}
/**
:name: handleFlashButton
*/
internal
func
handleFlashButton
(
button
:
UIButton
)
{
if
.
Back
==
captureSession
.
cameraPosition
{
var
img
:
UIImage
?
switch
captureSession
.
flashMode
{
case
.
Off
:
img
=
UIImage
(
named
:
"ic_flash_on_white"
)
captureSession
.
flashMode
=
.
On
case
.
On
:
img
=
UIImage
(
named
:
"ic_flash_auto_white"
)
captureSession
.
flashMode
=
.
Auto
case
.
Auto
:
img
=
UIImage
(
named
:
"ic_flash_off_white"
)
captureSession
.
flashMode
=
.
Off
}
flashButton
!.
setImage
(
img
,
forState
:
.
Normal
)
flashButton
!.
setImage
(
img
,
forState
:
.
Highlighted
)
}
}
/**
:name: prepareNavigationBarView
*/
private
func
prepareNavigationBarView
()
{
navigationBarView
.
backgroundColor
=
MaterialColor
.
black
.
colorWithAlphaComponent
(
0.3
)
navigationBarView
.
shadowDepth
=
.
None
navigationBarView
.
statusBarStyle
=
.
LightContent
// Title label.
let
titleLabel
:
UILabel
=
UILabel
()
titleLabel
.
hidden
=
true
titleLabel
.
textAlignment
=
.
Center
titleLabel
.
textColor
=
MaterialColor
.
white
titleLabel
.
font
=
RobotoFont
.
regularWithSize
(
20
)
navigationBarView
.
titleLabel
=
titleLabel
// Detail label
let
detailLabel
:
UILabel
=
UILabel
()
detailLabel
.
hidden
=
true
detailLabel
.
text
=
"Recording"
detailLabel
.
textAlignment
=
.
Center
detailLabel
.
textColor
=
MaterialColor
.
white
detailLabel
.
font
=
RobotoFont
.
regularWithSize
(
12
)
navigationBarView
.
detailLabel
=
detailLabel
navigationBarView
.
leftButtons
=
[
closeButton
!
]
navigationBarView
.
rightButtons
=
[
switchCameraButton
!
,
flashButton
!
]
addSubview
(
navigationBarView
)
navigationBarView
.
translatesAutoresizingMaskIntoConstraints
=
false
MaterialLayout
.
alignToParentHorizontally
(
self
,
child
:
navigationBarView
)
MaterialLayout
.
height
(
self
,
child
:
navigationBarView
,
height
:
70
)
}
/**
:name: prepareCaptureButton
*/
private
func
prepareCaptureButton
()
{
captureButton
=
FlatButton
()
captureButton
!.
pulseColor
=
MaterialColor
.
white
captureButton
!.
pulseFill
=
true
captureButton
!.
backgroundColor
=
MaterialColor
.
red
.
darken1
.
colorWithAlphaComponent
(
0.3
)
captureButton
!.
borderWidth
=
.
Border2
captureButton
!.
borderColor
=
MaterialColor
.
white
captureButton
!.
shadowDepth
=
.
None
captureButton
!.
addTarget
(
self
,
action
:
"handleCaptureButton:"
,
forControlEvents
:
.
TouchUpInside
)
addSubview
(
captureButton
!
)
captureButton
!.
translatesAutoresizingMaskIntoConstraints
=
false
MaterialLayout
.
alignFromBottomRight
(
self
,
child
:
captureButton
!
,
bottom
:
24
,
right
:
(
bounds
.
width
-
72
)
/
2
)
MaterialLayout
.
size
(
self
,
child
:
captureButton
!
,
width
:
72
,
height
:
72
)
}
/**
:name: prepareCameraButton
*/
private
func
prepareCameraButton
()
{
let
img4
:
UIImage
?
=
UIImage
(
named
:
"ic_photo_camera_white_36pt"
)
cameraButton
=
FlatButton
()
cameraButton
!.
pulseColor
=
nil
cameraButton
!.
setImage
(
img4
,
forState
:
.
Normal
)
cameraButton
!.
setImage
(
img4
,
forState
:
.
Highlighted
)
cameraButton
!.
addTarget
(
self
,
action
:
"handleCameraButton:"
,
forControlEvents
:
.
TouchUpInside
)
addSubview
(
cameraButton
!
)
cameraButton
!.
translatesAutoresizingMaskIntoConstraints
=
false
MaterialLayout
.
alignFromBottomLeft
(
self
,
child
:
cameraButton
!
,
bottom
:
24
,
left
:
24
)
}
/**
:name: prepareVideoButton
*/
private
func
prepareVideoButton
()
{
let
img5
:
UIImage
?
=
UIImage
(
named
:
"ic_videocam_white_36pt"
)
videoButton
=
FlatButton
()
videoButton
!.
pulseColor
=
nil
videoButton
!.
setImage
(
img5
,
forState
:
.
Normal
)
videoButton
!.
setImage
(
img5
,
forState
:
.
Highlighted
)
videoButton
!.
addTarget
(
self
,
action
:
"handleVideoButton:"
,
forControlEvents
:
.
TouchUpInside
)
addSubview
(
videoButton
!
)
videoButton
!.
translatesAutoresizingMaskIntoConstraints
=
false
MaterialLayout
.
alignFromBottomRight
(
self
,
child
:
videoButton
!
,
bottom
:
24
,
right
:
24
)
}
/**
:name: prepareCloseButton
*/
private
func
prepareCloseButton
()
{
let
img
:
UIImage
?
=
UIImage
(
named
:
"ic_close_white"
)
closeButton
=
FlatButton
()
closeButton
!.
pulseColor
=
nil
closeButton
!.
setImage
(
img
,
forState
:
.
Normal
)
closeButton
!.
setImage
(
img
,
forState
:
.
Highlighted
)
}
/**
:name: prepareSwitchCameraButton
*/
private
func
prepareSwitchCameraButton
()
{
let
img
:
UIImage
?
=
UIImage
(
named
:
"ic_camera_front_white"
)
switchCameraButton
=
FlatButton
()
switchCameraButton
!.
pulseColor
=
nil
switchCameraButton
!.
setImage
(
img
,
forState
:
.
Normal
)
switchCameraButton
!.
setImage
(
img
,
forState
:
.
Highlighted
)
switchCameraButton
!.
addTarget
(
self
,
action
:
"handleSwitchCameraButton:"
,
forControlEvents
:
.
TouchUpInside
)
}
/**
:name: prepareFlashButton
*/
private
func
prepareFlashButton
()
{
captureSession
.
flashMode
=
.
Auto
let
img
:
UIImage
?
=
UIImage
(
named
:
"ic_flash_auto_white"
)
flashButton
=
FlatButton
()
flashButton
!.
pulseColor
=
nil
flashButton
!.
setImage
(
img
,
forState
:
.
Normal
)
flashButton
!.
setImage
(
img
,
forState
:
.
Highlighted
)
flashButton
!.
addTarget
(
self
,
action
:
"handleFlashButton:"
,
forControlEvents
:
.
TouchUpInside
)
}
}
Sources/CapturePreviewView.swift
View file @
d3b4ccc1
...
...
@@ -19,152 +19,26 @@
import
UIKit
import
AVFoundation
@objc(CapturePreviewViewDelegate)
public
protocol
CapturePreviewViewDelegate
:
MaterialDelegate
{
public
class
CapturePreviewView
:
MaterialView
{
/**
:name:
capturePreviewViewDidTapToFocusAtPoint
:name:
layerClass
*/
optional
func
capturePreviewViewDidTapToFocusAtPoint
(
capturePreviewView
:
CapturePreviewView
,
point
:
CGPoint
)
/**
:name: capturePreviewViewDidTapToExposeAtPoint
*/
optional
func
capturePreviewViewDidTapToExposeAtPoint
(
capturePreviewView
:
CapturePreviewView
,
point
:
CGPoint
)
/**
:name: capturePreviewViewDidTapToResetAtPoint
*/
optional
func
capturePreviewViewDidTapToResetAtPoint
(
capturePreviewView
:
CapturePreviewView
,
point
:
CGPoint
)
}
public
class
CapturePreviewView
:
MaterialView
,
UIGestureRecognizerDelegate
{
/**
:name: tapToFocusGesture
*/
private
var
tapToFocusGesture
:
UITapGestureRecognizer
?
/**
:name: tapToExposeGesture
*/
private
var
tapToExposeGesture
:
UITapGestureRecognizer
?
/**
:name: tapToResetGesture
*/
private
var
tapToResetGesture
:
UITapGestureRecognizer
?
/**
:name: previewLayer
*/
public
private(set)
lazy
var
previewLayer
:
AVCaptureVideoPreviewLayer
=
AVCaptureVideoPreviewLayer
()
/**
:name: capture
*/
public
private(set)
lazy
var
captureSession
:
CaptureSession
=
CaptureSession
()
/**
:name: tapToFocusEnabled
*/
public
var
tapToFocusEnabled
:
Bool
{
didSet
{
if
tapToFocusEnabled
{
tapToResetEnabled
=
true
prepareTapGesture
(
&
tapToFocusGesture
,
numberOfTapsRequired
:
1
,
numberOfTouchesRequired
:
1
,
selector
:
"handleTapToFocusGesture:"
)
if
let
v
:
UITapGestureRecognizer
=
tapToExposeGesture
{
tapToFocusGesture
!.
requireGestureRecognizerToFail
(
v
)
}
}
else
{
removeTapGesture
(
&
tapToFocusGesture
)
}
}
}
/**
:name: tapToExposeEnabled
*/
public
var
tapToExposeEnabled
:
Bool
{
didSet
{
if
tapToExposeEnabled
{
tapToResetEnabled
=
true
prepareTapGesture
(
&
tapToExposeGesture
,
numberOfTapsRequired
:
2
,
numberOfTouchesRequired
:
1
,
selector
:
"handleTapToExposeGesture:"
)
if
let
v
:
UITapGestureRecognizer
=
tapToFocusGesture
{
v
.
requireGestureRecognizerToFail
(
tapToExposeGesture
!
)
}
}
else
{
removeTapGesture
(
&
tapToExposeGesture
)
}
}
}
/**
:name: tapToResetEnabled
*/
public
var
tapToResetEnabled
:
Bool
{
didSet
{
if
tapToResetEnabled
{
prepareTapGesture
(
&
tapToResetGesture
,
numberOfTapsRequired
:
2
,
numberOfTouchesRequired
:
2
,
selector
:
"handleTapToResetGesture:"
)
if
let
v
:
UITapGestureRecognizer
=
tapToFocusGesture
{
v
.
requireGestureRecognizerToFail
(
tapToResetGesture
!
)
}
if
let
v
:
UITapGestureRecognizer
=
tapToExposeGesture
{
v
.
requireGestureRecognizerToFail
(
tapToResetGesture
!
)
}
}
else
{
removeTapGesture
(
&
tapToResetGesture
)
}
}
}
/**
:name: init
*/
public
required
init
?(
coder
aDecoder
:
NSCoder
)
{
tapToFocusEnabled
=
true
tapToExposeEnabled
=
true
tapToResetEnabled
=
true
super
.
init
(
coder
:
aDecoder
)
}
/**
:name: init
*/
public
override
init
(
frame
:
CGRect
)
{
tapToFocusEnabled
=
true
tapToExposeEnabled
=
true
tapToResetEnabled
=
true
super
.
init
(
frame
:
frame
)
}
/**
:name: init
*/
public
convenience
init
()
{
self
.
init
(
frame
:
CGRectNull
)
}
/**
:name: layoutSublayersOfLayer
*/
public
override
func
layoutSublayersOfLayer
(
layer
:
CALayer
)
{
super
.
layoutSublayersOfLayer
(
layer
)
if
self
.
layer
==
layer
{
layoutPreviewLayer
()
}
public
override
class
func
layerClass
()
->
AnyClass
{
return
AVCaptureVideoPreviewLayer
.
self
}
/**
:name: captureDevicePointOfInterestForPoint
*/
public
func
captureDevicePointOfInterestForPoint
(
point
:
CGPoint
)
->
CGPoint
{
return
previewLayer
.
captureDevicePointOfInterestForPoint
(
point
)
return
(
layer
as!
AVCaptureVideoPreviewLayer
)
.
captureDevicePointOfInterestForPoint
(
point
)
}
/**
:name: pointForCaptureDevicePointOfInterest
*/
public
func
pointForCaptureDevicePointOfInterest
(
point
:
CGPoint
)
->
CGPoint
{
return
previewLayer
.
pointForCaptureDevicePointOfInterest
(
point
)
return
(
layer
as!
AVCaptureVideoPreviewLayer
)
.
pointForCaptureDevicePointOfInterest
(
point
)
}
/**
...
...
@@ -173,79 +47,15 @@ public class CapturePreviewView : MaterialView, UIGestureRecognizerDelegate {
public
override
func
prepareView
()
{
super
.
prepareView
()
preparePreviewLayer
()
tapToFocusEnabled
=
true
tapToExposeEnabled
=
true
}
/**
:name: handleTapToFocusGesture
*/
internal
func
handleTapToFocusGesture
(
recognizer
:
UITapGestureRecognizer
)
{
if
tapToFocusEnabled
&&
captureSession
.
cameraSupportsTapToFocus
{
let
point
:
CGPoint
=
recognizer
.
locationInView
(
self
)
captureSession
.
focusAtPoint
(
captureDevicePointOfInterestForPoint
(
point
))
(
delegate
as?
CapturePreviewViewDelegate
)?
.
capturePreviewViewDidTapToFocusAtPoint
?(
self
,
point
:
point
)
}
}
/**
:name: handleTapToExposeGesture
*/
internal
func
handleTapToExposeGesture
(
recognizer
:
UITapGestureRecognizer
)
{
if
tapToExposeEnabled
&&
captureSession
.
cameraSupportsTapToExpose
{
let
point
:
CGPoint
=
recognizer
.
locationInView
(
self
)
captureSession
.
exposeAtPoint
(
captureDevicePointOfInterestForPoint
(
point
))
(
delegate
as?
CapturePreviewViewDelegate
)?
.
capturePreviewViewDidTapToExposeAtPoint
?(
self
,
point
:
point
)
}
}
/**
:name: handleTapToResetGesture
*/
internal
func
handleTapToResetGesture
(
recognizer
:
UITapGestureRecognizer
)
{
if
tapToResetEnabled
{
captureSession
.
resetFocusAndExposureModes
()
(
delegate
as?
CapturePreviewViewDelegate
)?
.
capturePreviewViewDidTapToResetAtPoint
?(
self
,
point
:
pointForCaptureDevicePointOfInterest
(
CGPointMake
(
0.5
,
0.5
)))
}
}
/**
:name: preparePreviewLayer
*/
private
func
preparePreviewLayer
()
{
previewLayer
.
session
=
captureSession
.
session
visualLayer
.
addSublayer
(
previewLayer
)
}
/**
:name: layoutPreviewLayer
*/
private
func
layoutPreviewLayer
()
{
previewLayer
.
frame
=
visualLayer
.
bounds
previewLayer
.
position
=
CGPointMake
(
width
/
2
,
height
/
2
)
previewLayer
.
cornerRadius
=
visualLayer
.
cornerRadius
previewLayer
.
videoGravity
=
AVLayerVideoGravityResizeAspectFill
}
/**
:name: prepareTapGesture
*/
private
func
prepareTapGesture
(
inout
gesture
:
UITapGestureRecognizer
?,
numberOfTapsRequired
:
Int
,
numberOfTouchesRequired
:
Int
,
selector
:
Selector
)
{
removeTapGesture
(
&
gesture
)
gesture
=
UITapGestureRecognizer
(
target
:
self
,
action
:
selector
)
gesture
!.
delegate
=
self
gesture
!.
numberOfTapsRequired
=
numberOfTapsRequired
gesture
!.
numberOfTouchesRequired
=
numberOfTouchesRequired
addGestureRecognizer
(
gesture
!
)
}
/**
:name: removeTapToFocusGesture
*/
private
func
removeTapGesture
(
inout
gesture
:
UITapGestureRecognizer
?)
{
if
let
v
:
UIGestureRecognizer
=
gesture
{
removeGestureRecognizer
(
v
)
gesture
=
nil
}
layer
.
addAnimation
(
MaterialAnimation
.
transition
(
.
Fade
),
forKey
:
kCATransition
)
layer
.
backgroundColor
=
MaterialColor
.
black
.
CGColor
layer
.
masksToBounds
=
true
(
layer
as!
AVCaptureVideoPreviewLayer
)
.
videoGravity
=
AVLayerVideoGravityResizeAspectFill
}
}
\ No newline at end of file
Sources/CaptureSession.swift
View file @
d3b4ccc1
...
...
@@ -123,9 +123,9 @@ public protocol CaptureSessionDelegate {
@objc(CaptureSession)
public
class
CaptureSession
:
NSObject
,
AVCaptureFileOutputRecordingDelegate
{
/**
:name:
video
Queue
:name:
session
Queue
*/
private
lazy
var
videoQueue
:
dispatch_queue_t
=
dispatch_queue_create
(
"io.materialkit.CaptureSession"
,
nil
)
private
lazy
var
sessionQueue
:
dispatch_queue_t
=
dispatch_queue_create
(
"io.materialkit.CaptureSession"
,
DISPATCH_QUEUE_SERIAL
)
/**
:name: activeVideoInput
...
...
@@ -182,15 +182,6 @@ public class CaptureSession : NSObject, AVCaptureFileOutputRecordingDelegate {
}
/**
:name: init
*/
public
override
init
()
{
sessionPreset
=
.
PresetHigh
super
.
init
()
prepareSession
()
}
/**
:name: inactiveCamera
*/
public
var
inactiveCamera
:
AVCaptureDevice
?
{
...
...
@@ -368,11 +359,20 @@ public class CaptureSession : NSObject, AVCaptureFileOutputRecordingDelegate {
public
weak
var
delegate
:
CaptureSessionDelegate
?
/**
:name: init
*/
public
override
init
()
{
sessionPreset
=
.
PresetHigh
super
.
init
()
prepareSession
()
}
/**
:name: startSession
*/
public
func
startSession
()
{
if
!
isRunning
{
dispatch_async
(
video
Queue
)
{
dispatch_async
(
session
Queue
)
{
self
.
session
.
startRunning
()
}
}
...
...
@@ -383,7 +383,7 @@ public class CaptureSession : NSObject, AVCaptureFileOutputRecordingDelegate {
*/
public
func
stopSession
()
{
if
isRunning
{
dispatch_async
(
video
Queue
)
{
dispatch_async
(
session
Queue
)
{
self
.
session
.
stopRunning
()
}
}
...
...
@@ -542,14 +542,16 @@ public class CaptureSession : NSObject, AVCaptureFileOutputRecordingDelegate {
:name: captureStillImage
*/
public
func
captureStillImage
()
{
let
connection
:
AVCaptureConnection
=
imageOutput
.
connectionWithMediaType
(
AVMediaTypeVideo
)
connection
.
videoOrientation
=
currentVideoOrientation
imageOutput
.
captureStillImageAsynchronouslyFromConnection
(
connection
)
{
(
sampleBuffer
:
CMSampleBuffer
!
,
error
:
NSError
!
)
->
Void
in
if
nil
==
error
{
let
data
:
NSData
=
AVCaptureStillImageOutput
.
jpegStillImageNSDataRepresentation
(
sampleBuffer
)
self
.
delegate
?
.
captureStillImageAsynchronously
?(
self
,
image
:
UIImage
(
data
:
data
)
!
)
}
else
{
self
.
delegate
?
.
captureStillImageAsynchronouslyFailedWithError
?(
self
,
error
:
error
!
)
dispatch_async
(
sessionQueue
)
{
let
connection
:
AVCaptureConnection
=
self
.
imageOutput
.
connectionWithMediaType
(
AVMediaTypeVideo
)
connection
.
videoOrientation
=
self
.
currentVideoOrientation
self
.
imageOutput
.
captureStillImageAsynchronouslyFromConnection
(
connection
)
{
(
sampleBuffer
:
CMSampleBuffer
!
,
error
:
NSError
!
)
->
Void
in
if
nil
==
error
{
let
data
:
NSData
=
AVCaptureStillImageOutput
.
jpegStillImageNSDataRepresentation
(
sampleBuffer
)
self
.
delegate
?
.
captureStillImageAsynchronously
?(
self
,
image
:
UIImage
(
data
:
data
)
!
)
}
else
{
self
.
delegate
?
.
captureStillImageAsynchronouslyFailedWithError
?(
self
,
error
:
error
!
)
}
}
}
}
...
...
@@ -559,24 +561,26 @@ public class CaptureSession : NSObject, AVCaptureFileOutputRecordingDelegate {
*/
public
func
startRecording
()
{
if
!
self
.
isRecording
{
let
connection
:
AVCaptureConnection
=
self
.
movieOutput
.
connectionWithMediaType
(
AVMediaTypeVideo
)
connection
.
videoOrientation
=
self
.
currentVideoOrientation
connection
.
preferredVideoStabilizationMode
=
.
Auto
let
device
:
AVCaptureDevice
=
self
.
activeCamera
!
if
device
.
smoothAutoFocusSupported
{
do
{
try
device
.
lockForConfiguration
()
device
.
smoothAutoFocusEnabled
=
true
device
.
unlockForConfiguration
()
}
catch
let
e
as
NSError
{
self
.
delegate
?
.
captureSessionFailedWithError
?(
self
,
error
:
e
)
dispatch_async
(
sessionQueue
)
{
let
connection
:
AVCaptureConnection
=
self
.
movieOutput
.
connectionWithMediaType
(
AVMediaTypeVideo
)
connection
.
videoOrientation
=
self
.
currentVideoOrientation
connection
.
preferredVideoStabilizationMode
=
.
Auto
let
device
:
AVCaptureDevice
=
self
.
activeCamera
!
if
device
.
smoothAutoFocusSupported
{
do
{
try
device
.
lockForConfiguration
()
device
.
smoothAutoFocusEnabled
=
true
device
.
unlockForConfiguration
()
}
catch
let
e
as
NSError
{
self
.
delegate
?
.
captureSessionFailedWithError
?(
self
,
error
:
e
)
}
}
self
.
movieOutputURL
=
self
.
uniqueURL
()
if
let
v
:
NSURL
=
self
.
movieOutputURL
{
self
.
movieOutput
.
startRecordingToOutputFileURL
(
v
,
recordingDelegate
:
self
)
}
}
self
.
movieOutputURL
=
self
.
uniqueURL
()
if
let
v
:
NSURL
=
self
.
movieOutputURL
{
self
.
movieOutput
.
startRecordingToOutputFileURL
(
v
,
recordingDelegate
:
self
)
}
}
}
...
...
Sources/CaptureView.swift
View file @
d3b4ccc1
...
...
@@ -17,154 +17,300 @@
//
import
UIKit
import
AVFoundation
public
class
CaptureView
:
MaterialView
,
CapturePreviewViewDelegate
{
@objc(CaptureViewDelegate)
public
protocol
CaptureViewDelegate
:
MaterialDelegate
{
/**
:name: captureViewDidStartRecordTimer
*/
optional
func
captureViewDidStartRecordTimer
(
captureView
:
CaptureView
)
/**
:name: captureViewDidUpdateRecordTimer
*/
optional
func
captureViewDidUpdateRecordTimer
(
captureView
:
CaptureView
,
duration
:
CMTime
,
time
:
Double
,
hours
:
Int
,
minutes
:
Int
,
seconds
:
Int
)
/**
:name: captureViewDidStopRecordTimer
*/
optional
func
captureViewDidStopRecordTimer
(
captureView
:
CaptureView
,
duration
:
CMTime
,
time
:
Double
,
hours
:
Int
,
minutes
:
Int
,
seconds
:
Int
)
/**
:name: captureViewDidTapToFocusAtPoint
*/
optional
func
captureViewDidTapToFocusAtPoint
(
captureView
:
CaptureView
,
point
:
CGPoint
)
/**
:name: captureViewDidTapToExposeAtPoint
*/
optional
func
captureViewDidTapToExposeAtPoint
(
captureView
:
CaptureView
,
point
:
CGPoint
)
/**
:name: captureViewDidTapToResetAtPoint
*/
optional
func
captureViewDidTapToResetAtPoint
(
captureView
:
CaptureView
,
point
:
CGPoint
)
}
public
class
CaptureView
:
MaterialView
,
UIGestureRecognizerDelegate
{
/**
:name: timer
*/
private
var
timer
:
NSTimer
?
/**
:name: tapToFocusGesture
*/
private
var
tapToFocusGesture
:
UITapGestureRecognizer
?
/**
:name: tapToExposeGesture
*/
private
var
tapToExposeGesture
:
UITapGestureRecognizer
?
/**
:name: tapToResetGesture
*/
private
var
tapToResetGesture
:
UITapGestureRecognizer
?
/**
:name: tapToResetEnabled
*/
private
var
tapToResetEnabled
:
Bool
=
false
{
didSet
{
if
tapToResetEnabled
{
prepareTapGesture
(
&
tapToResetGesture
,
numberOfTapsRequired
:
2
,
numberOfTouchesRequired
:
2
,
selector
:
"handleTapToResetGesture:"
)
if
let
v
:
UITapGestureRecognizer
=
tapToFocusGesture
{
v
.
requireGestureRecognizerToFail
(
tapToResetGesture
!
)
}
if
let
v
:
UITapGestureRecognizer
=
tapToExposeGesture
{
v
.
requireGestureRecognizerToFail
(
tapToResetGesture
!
)
}
}
else
{
removeTapGesture
(
&
tapToResetGesture
)
}
}
}
/**
:name: previewView
*/
public
private(set)
lazy
var
previewView
:
CapturePreviewView
=
CapturePreviewView
()
/**
:name: focusLayer
:name: capture
*/
public
private(set)
lazy
var
captureSession
:
CaptureSession
=
CaptureSession
()
/**
:name: focusView
*/
public
var
focusView
:
MaterialView
?
{
didSet
{
if
nil
==
focusView
{
removeTapGesture
(
&
tapToFocusGesture
)
}
else
{
tapToResetEnabled
=
true
prepareFocusView
()
prepareTapGesture
(
&
tapToFocusGesture
,
numberOfTapsRequired
:
1
,
numberOfTouchesRequired
:
1
,
selector
:
"handleTapToFocusGesture:"
)
if
let
v
:
UITapGestureRecognizer
=
tapToExposeGesture
{
tapToFocusGesture
!.
requireGestureRecognizerToFail
(
v
)
}
}
}
}
/**
:name: exposureView
*/
public
private(set)
lazy
var
focusLayer
:
MaterialLayer
=
MaterialLayer
()
public
var
exposureView
:
MaterialView
?
{
didSet
{
if
nil
==
exposureView
{
removeTapGesture
(
&
tapToExposeGesture
)
}
else
{
tapToResetEnabled
=
true
prepareExposureView
()
prepareTapGesture
(
&
tapToExposeGesture
,
numberOfTapsRequired
:
2
,
numberOfTouchesRequired
:
1
,
selector
:
"handleTapToExposeGesture:"
)
if
let
v
:
UITapGestureRecognizer
=
tapToFocusGesture
{
v
.
requireGestureRecognizerToFail
(
tapToExposeGesture
!
)
}
}
}
}
/**
:name:
exposureLayer
:name:
closeButton
*/
public
private(set)
lazy
var
exposureLayer
:
MaterialLayer
=
MaterialLayer
()
public
var
closeButton
:
MaterialButton
?
/**
:name: cameraButton
*/
public
var
cameraButton
:
MaterialButton
?
/**
:name: captureButton
*/
public
var
captureButton
:
UI
Button
?
public
var
captureButton
:
Material
Button
?
/**
:name:
switchCameras
Button
:name:
video
Button
*/
public
var
switchCamerasButton
:
UIButton
?
public
var
videoButton
:
MaterialButton
?
/**
:name: switchCameraButton
*/
public
var
switchCameraButton
:
MaterialButton
?
/**
:name: flashButton
*/
public
var
flashButton
:
UI
Button
?
public
var
flashButton
:
Material
Button
?
/**
:name:
captureSession
:name:
prepareView
*/
public
var
captureSession
:
CaptureSession
{
return
previewView
.
captureSession
public
override
func
prepareView
()
{
super
.
prepareView
()
prepareCapturePreviewView
()
}
/**
:name:
init
:name:
startTimer
*/
public
convenience
init
()
{
self
.
init
(
frame
:
CGRectNull
)
internal
func
startTimer
()
{
timer
?
.
invalidate
()
timer
=
NSTimer
(
timeInterval
:
0.5
,
target
:
self
,
selector
:
"updateTimer"
,
userInfo
:
nil
,
repeats
:
true
)
NSRunLoop
.
mainRunLoop
()
.
addTimer
(
timer
!
,
forMode
:
NSRunLoopCommonModes
)
(
delegate
as?
CaptureViewDelegate
)?
.
captureViewDidStartRecordTimer
?(
self
)
}
/**
:name:
layoutSublayersOfLay
er
:name:
updateTim
er
*/
public
override
func
layoutSublayersOfLayer
(
layer
:
CALayer
)
{
super
.
layoutSublayersOfLayer
(
layer
)
if
self
.
layer
==
layer
{
}
internal
func
updateTimer
()
{
let
duration
:
CMTime
=
captureSession
.
recordedDuration
let
time
:
Double
=
CMTimeGetSeconds
(
duration
)
let
hours
:
Int
=
Int
(
time
/
3600
)
let
minutes
:
Int
=
Int
((
time
/
60
)
%
60
)
let
seconds
:
Int
=
Int
(
time
%
60
)
(
delegate
as?
CaptureViewDelegate
)?
.
captureViewDidUpdateRecordTimer
?(
self
,
duration
:
duration
,
time
:
time
,
hours
:
hours
,
minutes
:
minutes
,
seconds
:
seconds
)
}
/**
:name:
reloadView
:name:
stopTimer
*/
public
func
reloadView
()
{
previewView
.
removeFromSuperview
()
addSubview
(
previewView
)
MaterialLayout
.
alignToParent
(
self
,
child
:
previewView
)
internal
func
stopTimer
()
{
let
duration
:
CMTime
=
captureSession
.
recordedDuration
let
time
:
Double
=
CMTimeGetSeconds
(
duration
)
let
hours
:
Int
=
Int
(
time
/
3600
)
let
minutes
:
Int
=
Int
((
time
/
60
)
%
60
)
let
seconds
:
Int
=
Int
(
time
%
60
)
timer
?
.
invalidate
()
timer
=
nil
(
delegate
as?
CaptureViewDelegate
)?
.
captureViewDidStopRecordTimer
?(
self
,
duration
:
duration
,
time
:
time
,
hours
:
hours
,
minutes
:
minutes
,
seconds
:
seconds
)
}
/**
:name:
capturePreviewViewDidTapToFocusAtPoint
:name:
handleTapToFocusGesture
*/
public
func
capturePreviewViewDidTapToFocusAtPoint
(
capturePreviewView
:
CapturePreviewView
,
point
:
CGPoint
)
{
MaterialAnimation
.
animationDisabled
{
self
.
focusLayer
.
position
=
point
self
.
focusLayer
.
hidden
=
false
}
MaterialAnimation
.
animateWithDuration
(
0.25
,
animations
:
{
self
.
focusLayer
.
transform
=
CATransform3DMakeScale
(
0
,
0
,
1
)
})
{
MaterialAnimation
.
animationDisabled
{
self
.
focusLayer
.
hidden
=
true
self
.
focusLayer
.
transform
=
CATransform3DIdentity
internal
func
handleTapToFocusGesture
(
recognizer
:
UITapGestureRecognizer
)
{
if
let
v
:
MaterialView
=
focusView
{
if
captureSession
.
cameraSupportsTapToFocus
{
let
point
:
CGPoint
=
recognizer
.
locationInView
(
self
)
captureSession
.
focusAtPoint
(
previewView
.
captureDevicePointOfInterestForPoint
(
point
))
MaterialAnimation
.
animationDisabled
{
v
.
layer
.
transform
=
CATransform3DIdentity
v
.
position
=
point
v
.
hidden
=
false
}
MaterialAnimation
.
animateWithDuration
(
0.25
,
animations
:
{
v
.
layer
.
transform
=
CATransform3DMakeScale
(
0.5
,
0.5
,
1
)
})
{
MaterialAnimation
.
delay
(
0.4
)
{
MaterialAnimation
.
animationDisabled
{
v
.
hidden
=
true
}
}
}
(
delegate
as?
CaptureViewDelegate
)?
.
captureViewDidTapToFocusAtPoint
?(
self
,
point
:
point
)
}
}
}
/**
:name:
capturePreviewViewDidTapToExposeAtPoint
:name:
handleTapToExposeGesture
*/
public
func
capturePreviewViewDidTapToExposeAtPoint
(
capturePreviewView
:
CapturePreviewView
,
point
:
CGPoint
)
{
MaterialAnimation
.
animationDisabled
{
self
.
exposureLayer
.
position
=
point
self
.
exposureLayer
.
hidden
=
false
internal
func
handleTapToExposeGesture
(
recognizer
:
UITapGestureRecognizer
)
{
if
nil
!=
exposureView
&&
captureSession
.
cameraSupportsTapToExpose
{
let
point
:
CGPoint
=
recognizer
.
locationInView
(
self
)
captureSession
.
exposeAtPoint
(
previewView
.
captureDevicePointOfInterestForPoint
(
point
))
(
delegate
as?
CaptureViewDelegate
)?
.
captureViewDidTapToExposeAtPoint
?(
self
,
point
:
point
)
}
MaterialAnimation
.
animateWithDuration
(
0.25
,
animations
:
{
self
.
exposureLayer
.
transform
=
CATransform3DMakeScale
(
0
,
0
,
1
)
})
{
MaterialAnimation
.
animationDisabled
{
self
.
exposureLayer
.
hidden
=
true
self
.
exposureLayer
.
transform
=
CATransform3DIdentity
}
}
/**
:name: handleTapToResetGesture
*/
internal
func
handleTapToResetGesture
(
recognizer
:
UITapGestureRecognizer
)
{
if
tapToResetEnabled
{
captureSession
.
resetFocusAndExposureModes
()
let
point
:
CGPoint
=
previewView
.
pointForCaptureDevicePointOfInterest
(
CGPointMake
(
0.5
,
0.5
))
(
delegate
as?
CaptureViewDelegate
)?
.
captureViewDidTapToResetAtPoint
?(
self
,
point
:
point
)
}
}
/**
:name:
capturePreviewViewDidTapToResetAtPoint
:name:
prepareTapGesture
*/
public
func
capturePreviewViewDidTapToResetAtPoint
(
capturePreviewView
:
CapturePreviewView
,
point
:
CGPoint
)
{
capturePreviewViewDidTapToFocusAtPoint
(
capturePreviewView
,
point
:
point
)
capturePreviewViewDidTapToExposeAtPoint
(
capturePreviewView
,
point
:
point
)
private
func
prepareTapGesture
(
inout
gesture
:
UITapGestureRecognizer
?,
numberOfTapsRequired
:
Int
,
numberOfTouchesRequired
:
Int
,
selector
:
Selector
)
{
removeTapGesture
(
&
gesture
)
gesture
=
UITapGestureRecognizer
(
target
:
self
,
action
:
selector
)
gesture
!.
delegate
=
self
gesture
!.
numberOfTapsRequired
=
numberOfTapsRequired
gesture
!.
numberOfTouchesRequired
=
numberOfTouchesRequired
addGestureRecognizer
(
gesture
!
)
}
/**
:name:
prepareView
:name:
removeTapToFocusGesture
*/
public
override
func
prepareView
()
{
super
.
prepareView
()
preparePreviewView
()
prepareFocusLayer
()
prepareExposureLayer
()
reloadView
()
private
func
removeTapGesture
(
inout
gesture
:
UITapGestureRecognizer
?)
{
if
let
v
:
UIGestureRecognizer
=
gesture
{
removeGestureRecognizer
(
v
)
gesture
=
nil
}
}
/**
:name: preparePreviewView
:name: prepare
Capture
PreviewView
*/
private
func
preparePreviewView
()
{
private
func
prepareCapturePreviewView
()
{
(
previewView
.
layer
as!
AVCaptureVideoPreviewLayer
)
.
session
=
captureSession
.
session
captureSession
.
startSession
()
addSubview
(
previewView
)
previewView
.
translatesAutoresizingMaskIntoConstraints
=
false
previewView
.
delegate
=
self
previewView
.
captureSession
.
startSession
()
MaterialLayout
.
alignToParent
(
self
,
child
:
previewView
)
}
/**
:name: prepareFocus
Layer
:name: prepareFocus
View
*/
private
func
prepareFocusLayer
()
{
focusLayer
.
hidden
=
true
focusLayer
.
backgroundColor
=
MaterialColor
.
blue
.
base
.
colorWithAlphaComponent
(
0.25
)
.
CGColor
focusLayer
.
bounds
=
CGRectMake
(
0
,
0
,
150
,
150
)
focusLayer
.
cornerRadius
=
75
previewView
.
layer
.
addSublayer
(
focusLayer
)
private
func
prepareFocusView
()
{
if
let
v
:
MaterialView
=
focusView
{
addSubview
(
v
)
v
.
hidden
=
true
}
}
/**
:name: prepareExposure
Layer
:name: prepareExposure
View
*/
private
func
prepareExposureLayer
()
{
exposureLayer
.
hidden
=
true
exposureLayer
.
backgroundColor
=
MaterialColor
.
red
.
base
.
colorWithAlphaComponent
(
0.25
)
.
CGColor
exposureLayer
.
bounds
=
CGRectMake
(
0
,
0
,
150
,
150
)
exposureLayer
.
cornerRadius
=
75
previewView
.
layer
.
addSublayer
(
exposureLayer
)
private
func
prepareExposureView
()
{
if
let
v
:
MaterialView
=
exposureView
{
addSubview
(
v
)
v
.
hidden
=
true
}
}
}
\ No newline at end of file
Sources/MaterialAnimation.swift
View file @
d3b4ccc1
...
...
@@ -49,8 +49,45 @@ public func MaterialAnimationFillModeToValue(mode: MaterialAnimationFillMode) ->
}
}
public
typealias
MaterialAnimationDelayCancelBlock
=
(
cancel
:
Bool
)
->
Void
public
struct
MaterialAnimation
{
/**
:name: delay
*/
public
static
func
delay
(
time
:
NSTimeInterval
,
completion
:
()
->
Void
)
->
MaterialAnimationDelayCancelBlock
?
{
func
dispatch_later
(
completion
:
()
->
Void
)
{
dispatch_after
(
dispatch_time
(
DISPATCH_TIME_NOW
,
Int64
(
time
*
Double
(
NSEC_PER_SEC
))),
dispatch_get_main_queue
(),
completion
)
}
var
cancelable
:
MaterialAnimationDelayCancelBlock
?
let
delayed
:
MaterialAnimationDelayCancelBlock
=
{
cancel
in
if
!
cancel
{
dispatch_async
(
dispatch_get_main_queue
(),
completion
)
}
cancelable
=
nil
}
cancelable
=
delayed
dispatch_later
{
cancelable
?(
cancel
:
false
)
}
return
cancelable
;
}
/**
:name: delayCancel
*/
public
static
func
delayCancel
(
completion
:
MaterialAnimationDelayCancelBlock
?)
{
completion
?(
cancel
:
true
)
}
/**
:name: animationDisabled
*/
public
static
func
animationDisabled
(
animations
:
(()
->
Void
))
{
...
...
@@ -81,4 +118,13 @@ public struct MaterialAnimation {
group
.
timingFunction
=
CAMediaTimingFunction
(
name
:
kCAMediaTimingFunctionEaseInEaseOut
)
return
group
}
/**
:name: animateWithDelay
*/
public
static
func
animateWithDelay
(
delay
d
:
CFTimeInterval
,
duration
:
CFTimeInterval
,
animations
:
(()
->
Void
),
options
:
UIViewAnimationOptions
?
=
nil
,
completion
:
(()
->
Void
)?
=
nil
)
{
delay
(
d
)
{
animateWithDuration
(
duration
,
animations
:
animations
,
options
:
options
,
completion
:
completion
)
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment