mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 11:23:48 +00:00
Camera and editor improvements
This commit is contained in:
parent
f0efd5e219
commit
62f92ee5af
@ -43,7 +43,7 @@ private struct CameraState {
|
|||||||
return CameraState(mode: mode, position: self.position, flashMode: self.flashMode, flashModeDidChange: self.flashModeDidChange, recording: self.recording, duration: self.duration)
|
return CameraState(mode: mode, position: self.position, flashMode: self.flashMode, flashModeDidChange: self.flashModeDidChange, recording: self.recording, duration: self.duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updatedPosition(_ mode: Camera.Position) -> CameraState {
|
func updatedPosition(_ position: Camera.Position) -> CameraState {
|
||||||
return CameraState(mode: self.mode, position: position, flashMode: self.flashMode, flashModeDidChange: self.flashModeDidChange, recording: self.recording, duration: self.duration)
|
return CameraState(mode: self.mode, position: position, flashMode: self.flashMode, flashModeDidChange: self.flashModeDidChange, recording: self.recording, duration: self.duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,13 +216,7 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
self.hapticFeedback.impact(.light)
|
self.hapticFeedback.impact(.light)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastFlipTimestamp: Double?
|
|
||||||
func togglePosition() {
|
func togglePosition() {
|
||||||
let currentTimestamp = CACurrentMediaTime()
|
|
||||||
if let lastFlipTimestamp = self.lastFlipTimestamp, currentTimestamp - lastFlipTimestamp < 2.0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.lastFlipTimestamp = currentTimestamp
|
|
||||||
self.camera.togglePosition()
|
self.camera.togglePosition()
|
||||||
self.hapticFeedback.impact(.light)
|
self.hapticFeedback.impact(.light)
|
||||||
}
|
}
|
||||||
@ -1334,7 +1328,7 @@ public class CameraScreen: ViewController {
|
|||||||
|
|
||||||
private var galleryController: ViewController?
|
private var galleryController: ViewController?
|
||||||
public func returnFromEditor() {
|
public func returnFromEditor() {
|
||||||
self.node.animateInFromEditor(toGallery: self.galleryController != nil)
|
self.node.animateInFromEditor(toGallery: self.galleryController?.displayNode.supernode != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func presentGallery(fromGesture: Bool = false) {
|
func presentGallery(fromGesture: Bool = false) {
|
||||||
@ -1377,6 +1371,8 @@ public class CameraScreen: ViewController {
|
|||||||
self.node.resumeCameraCapture()
|
self.node.resumeCameraCapture()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
self.galleryController = controller
|
||||||
|
}
|
||||||
controller.customModalStyleOverlayTransitionFactorUpdated = { [weak self, weak controller] transition in
|
controller.customModalStyleOverlayTransitionFactorUpdated = { [weak self, weak controller] transition in
|
||||||
if let self, let controller {
|
if let self, let controller {
|
||||||
let transitionFactor = controller.modalStyleOverlayTransitionFactor
|
let transitionFactor = controller.modalStyleOverlayTransitionFactor
|
||||||
@ -1386,8 +1382,6 @@ public class CameraScreen: ViewController {
|
|||||||
self.node.updateModalTransitionFactor(transitionFactor, transition: transition)
|
self.node.updateModalTransitionFactor(transitionFactor, transition: transition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.galleryController = controller
|
|
||||||
}
|
|
||||||
self.push(controller)
|
self.push(controller)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,6 +370,12 @@ final class CaptureControlsComponent: Component {
|
|||||||
|
|
||||||
private let lockImage = UIImage(bundleImageName: "Camera/LockIcon")
|
private let lockImage = UIImage(bundleImageName: "Camera/LockIcon")
|
||||||
|
|
||||||
|
private var lastFlipTimestamp: Double?
|
||||||
|
private var didFlip = false
|
||||||
|
|
||||||
|
private var wasBanding: Bool?
|
||||||
|
private var panBlobState: ShutterBlobView.BlobState?
|
||||||
|
|
||||||
private let hapticFeedback = HapticFeedback()
|
private let hapticFeedback = HapticFeedback()
|
||||||
|
|
||||||
public func matches(tag: Any) -> Bool {
|
public func matches(tag: Any) -> Bool {
|
||||||
@ -425,9 +431,6 @@ final class CaptureControlsComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var didFlip = false
|
|
||||||
private var wasBanding: Bool?
|
|
||||||
private var panBlobState: ShutterBlobView.BlobState?
|
|
||||||
@objc private func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
|
@objc private func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
|
||||||
guard let component = self.component else {
|
guard let component = self.component else {
|
||||||
return
|
return
|
||||||
@ -651,7 +654,15 @@ final class CaptureControlsComponent: Component {
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
minSize: CGSize(width: 44.0, height: 44.0),
|
minSize: CGSize(width: 44.0, height: 44.0),
|
||||||
action: {
|
action: { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let currentTimestamp = CACurrentMediaTime()
|
||||||
|
if let lastFlipTimestamp = self.lastFlipTimestamp, currentTimestamp - lastFlipTimestamp < 1.3 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.lastFlipTimestamp = currentTimestamp
|
||||||
component.flipTapped()
|
component.flipTapped()
|
||||||
flipAnimationAction.invoke(Void())
|
flipAnimationAction.invoke(Void())
|
||||||
}
|
}
|
||||||
|
@ -494,6 +494,10 @@ public final class MediaEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var isPlaying: Bool {
|
||||||
|
return (self.player?.rate ?? 0.0) > 0.0
|
||||||
|
}
|
||||||
|
|
||||||
public func play() {
|
public func play() {
|
||||||
self.player?.play()
|
self.player?.play()
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,8 @@ public enum EditorToolKey: Int32, CaseIterable {
|
|||||||
case highlightsTint
|
case highlightsTint
|
||||||
case blur
|
case blur
|
||||||
case curves
|
case curves
|
||||||
}
|
|
||||||
|
|
||||||
private let adjustmentToolsKeys: [EditorToolKey] = [
|
static let adjustmentToolsKeys: [EditorToolKey] = [
|
||||||
.enhance,
|
.enhance,
|
||||||
.brightness,
|
.brightness,
|
||||||
.contrast,
|
.contrast,
|
||||||
@ -35,7 +34,8 @@ private let adjustmentToolsKeys: [EditorToolKey] = [
|
|||||||
.vignette,
|
.vignette,
|
||||||
.grain,
|
.grain,
|
||||||
.sharpen
|
.sharpen
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
|
||||||
public final class MediaEditorValues: Codable, Equatable {
|
public final class MediaEditorValues: Codable, Equatable {
|
||||||
public static func == (lhs: MediaEditorValues, rhs: MediaEditorValues) -> Bool {
|
public static func == (lhs: MediaEditorValues, rhs: MediaEditorValues) -> Bool {
|
||||||
@ -75,9 +75,28 @@ public final class MediaEditorValues: Codable, Equatable {
|
|||||||
if lhs.entities != rhs.entities {
|
if lhs.entities != rhs.entities {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// if lhs.toolValues != rhs.toolValues {
|
|
||||||
// return false
|
|
||||||
// }
|
for key in EditorToolKey.allCases {
|
||||||
|
let lhsToolValue = lhs.toolValues[key]
|
||||||
|
let rhsToolValue = rhs.toolValues[key]
|
||||||
|
if (lhsToolValue == nil) != (rhsToolValue == nil) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if let lhsToolValue = lhsToolValue as? Float, let rhsToolValue = rhsToolValue as? Float {
|
||||||
|
return lhsToolValue != rhsToolValue
|
||||||
|
}
|
||||||
|
if let lhsToolValue = lhsToolValue as? BlurValue, let rhsToolValue = rhsToolValue as? BlurValue {
|
||||||
|
return lhsToolValue != rhsToolValue
|
||||||
|
}
|
||||||
|
if let lhsToolValue = lhsToolValue as? TintValue, let rhsToolValue = rhsToolValue as? TintValue {
|
||||||
|
return lhsToolValue != rhsToolValue
|
||||||
|
}
|
||||||
|
if let lhsToolValue = lhsToolValue as? CurvesValue, let rhsToolValue = rhsToolValue as? CurvesValue {
|
||||||
|
return lhsToolValue != rhsToolValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,7 +681,7 @@ public struct CurvesValue: Equatable, Codable {
|
|||||||
private let toolEpsilon: Float = 0.005
|
private let toolEpsilon: Float = 0.005
|
||||||
public extension MediaEditorValues {
|
public extension MediaEditorValues {
|
||||||
var hasAdjustments: Bool {
|
var hasAdjustments: Bool {
|
||||||
for key in adjustmentToolsKeys {
|
for key in EditorToolKey.adjustmentToolsKeys {
|
||||||
if let value = self.toolValues[key] as? Float, abs(value) > toolEpsilon {
|
if let value = self.toolValues[key] as? Float, abs(value) > toolEpsilon {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ final class VideoTextureSource: NSObject, TextureSource, AVPlayerItemOutputPullD
|
|||||||
}
|
}
|
||||||
|
|
||||||
func invalidate() {
|
func invalidate() {
|
||||||
self.playerItemOutput?.setDelegate(nil, queue: self.queue)
|
self.playerItemOutput?.setDelegate(nil, queue: nil)
|
||||||
self.playerItemOutput = nil
|
self.playerItemOutput = nil
|
||||||
self.playerItemObservation?.invalidate()
|
self.playerItemObservation?.invalidate()
|
||||||
self.playerItemStatusObservation?.invalidate()
|
self.playerItemStatusObservation?.invalidate()
|
||||||
|
@ -287,10 +287,14 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2)
|
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let view = self.inputPanel.view {
|
if let view = self.inputPanel.view {
|
||||||
if case .camera = source {
|
view.layer.animatePosition(from: CGPoint(x: 0.0, y: 44.0), to: .zero, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||||
|
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
|
view.layer.animateScale(from: 0.6, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let view = self.scrubber.view {
|
||||||
view.layer.animatePosition(from: CGPoint(x: 0.0, y: 44.0), to: .zero, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
view.layer.animatePosition(from: CGPoint(x: 0.0, y: 44.0), to: .zero, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||||
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
view.layer.animateScale(from: 0.6, to: 1.0, duration: 0.2)
|
view.layer.animateScale(from: 0.6, to: 1.0, duration: 0.2)
|
||||||
@ -327,8 +331,15 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
transition.setScale(view: view, scale: 0.1)
|
transition.setScale(view: view, scale: 0.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let view = self.inputPanel.view {
|
|
||||||
if case .camera = source {
|
if case .camera = source {
|
||||||
|
if let view = self.inputPanel.view {
|
||||||
|
view.layer.animatePosition(from: .zero, to: CGPoint(x: 0.0, y: 44.0), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
|
||||||
|
view.layer.animateAlpha(from: view.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||||
|
view.layer.animateScale(from: 1.0, to: 0.1, duration: 0.2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let view = self.scrubber.view {
|
||||||
view.layer.animatePosition(from: .zero, to: CGPoint(x: 0.0, y: 44.0), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
|
view.layer.animatePosition(from: .zero, to: CGPoint(x: 0.0, y: 44.0), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
|
||||||
view.layer.animateAlpha(from: view.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
view.layer.animateAlpha(from: view.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||||
view.layer.animateScale(from: 1.0, to: 0.1, duration: 0.2)
|
view.layer.animateScale(from: 1.0, to: 0.1, duration: 0.2)
|
||||||
@ -426,6 +437,7 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var isEditingCaption = false
|
||||||
func update(component: MediaEditorScreenComponent, availableSize: CGSize, state: State, environment: Environment<ViewControllerComponentContainer.Environment>, transition: Transition) -> CGSize {
|
func update(component: MediaEditorScreenComponent, availableSize: CGSize, state: State, environment: Environment<ViewControllerComponentContainer.Environment>, transition: Transition) -> CGSize {
|
||||||
guard !self.isDismissed else {
|
guard !self.isDismissed else {
|
||||||
return availableSize
|
return availableSize
|
||||||
@ -752,14 +764,23 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
|
|
||||||
let fadeTransition = Transition(animation: .curve(duration: 0.3, curve: .easeInOut))
|
let fadeTransition = Transition(animation: .curve(duration: 0.3, curve: .easeInOut))
|
||||||
if self.inputPanelExternalState.isEditing {
|
if self.inputPanelExternalState.isEditing {
|
||||||
component.mediaEditor?.stop()
|
|
||||||
fadeTransition.setAlpha(view: self.fadeView, alpha: 1.0)
|
fadeTransition.setAlpha(view: self.fadeView, alpha: 1.0)
|
||||||
} else {
|
} else {
|
||||||
component.mediaEditor?.play()
|
|
||||||
fadeTransition.setAlpha(view: self.fadeView, alpha: 0.0)
|
fadeTransition.setAlpha(view: self.fadeView, alpha: 0.0)
|
||||||
}
|
}
|
||||||
transition.setFrame(view: self.fadeView, frame: CGRect(origin: .zero, size: availableSize))
|
transition.setFrame(view: self.fadeView, frame: CGRect(origin: .zero, size: availableSize))
|
||||||
|
|
||||||
|
let isEditingCaption = self.inputPanelExternalState.isEditing
|
||||||
|
if self.isEditingCaption != isEditingCaption {
|
||||||
|
self.isEditingCaption = isEditingCaption
|
||||||
|
|
||||||
|
if isEditingCaption {
|
||||||
|
mediaEditor?.stop()
|
||||||
|
} else {
|
||||||
|
mediaEditor?.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var isEditingTextEntity = false
|
var isEditingTextEntity = false
|
||||||
var sizeSliderVisible = false
|
var sizeSliderVisible = false
|
||||||
var sizeValue: CGFloat?
|
var sizeValue: CGFloat?
|
||||||
@ -1130,6 +1151,8 @@ public final class MediaEditorScreen: ViewController {
|
|||||||
|
|
||||||
fileprivate var subject: MediaEditorScreen.Subject?
|
fileprivate var subject: MediaEditorScreen.Subject?
|
||||||
private var subjectDisposable: Disposable?
|
private var subjectDisposable: Disposable?
|
||||||
|
private var appInForegroundDisposable: Disposable?
|
||||||
|
private var wasPlaying = false
|
||||||
|
|
||||||
private let backgroundDimView: UIView
|
private let backgroundDimView: UIView
|
||||||
fileprivate let componentHost: ComponentView<ViewControllerComponentContainer.Environment>
|
fileprivate let componentHost: ComponentView<ViewControllerComponentContainer.Environment>
|
||||||
@ -1289,11 +1312,24 @@ public final class MediaEditorScreen: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.appInForegroundDisposable = (controller.context.sharedContext.applicationBindings.applicationInForeground
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] inForeground in
|
||||||
|
if let self, let mediaEditor = self.mediaEditor {
|
||||||
|
if inForeground && self.wasPlaying {
|
||||||
|
mediaEditor.play()
|
||||||
|
} else if !inForeground {
|
||||||
|
self.wasPlaying = mediaEditor.isPlaying
|
||||||
|
mediaEditor.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
self.subjectDisposable?.dispose()
|
self.subjectDisposable?.dispose()
|
||||||
self.gradientColorsDisposable?.dispose()
|
self.gradientColorsDisposable?.dispose()
|
||||||
|
self.appInForegroundDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setup(with subject: MediaEditorScreen.Subject) {
|
private func setup(with subject: MediaEditorScreen.Subject) {
|
||||||
@ -2254,6 +2290,10 @@ public final class MediaEditorScreen: ViewController {
|
|||||||
self.transitionOut = transitionOut
|
self.transitionOut = transitionOut
|
||||||
self.completion = completion
|
self.completion = completion
|
||||||
|
|
||||||
|
if let transitionIn, case .camera = transitionIn {
|
||||||
|
self.isSavingAvailable = true
|
||||||
|
}
|
||||||
|
|
||||||
super.init(navigationBarPresentationData: nil)
|
super.init(navigationBarPresentationData: nil)
|
||||||
|
|
||||||
self.navigationPresentation = .flatModal
|
self.navigationPresentation = .flatModal
|
||||||
@ -3094,7 +3134,7 @@ private final class ToolValueComponent: Component {
|
|||||||
self.state = state
|
self.state = state
|
||||||
|
|
||||||
let titleSize = self.title.update(
|
let titleSize = self.title.update(
|
||||||
transition: transition,
|
transition: .immediate,
|
||||||
component: AnyComponent(Text(
|
component: AnyComponent(Text(
|
||||||
text: component.title,
|
text: component.title,
|
||||||
font: Font.light(34.0),
|
font: Font.light(34.0),
|
||||||
@ -3116,11 +3156,11 @@ private final class ToolValueComponent: Component {
|
|||||||
self.addSubview(titleView)
|
self.addSubview(titleView)
|
||||||
}
|
}
|
||||||
transition.setPosition(view: titleView, position: titleFrame.center)
|
transition.setPosition(view: titleView, position: titleFrame.center)
|
||||||
transition.setBounds(view: titleView, bounds: CGRect(origin: .zero, size: titleFrame.size))
|
titleView.bounds = CGRect(origin: .zero, size: titleFrame.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
let valueSize = self.value.update(
|
let valueSize = self.value.update(
|
||||||
transition: transition,
|
transition: .immediate,
|
||||||
component: AnyComponent(Text(
|
component: AnyComponent(Text(
|
||||||
text: component.value,
|
text: component.value,
|
||||||
font: Font.with(size: 90.0, weight: .thin, traits: .monospacedNumbers),
|
font: Font.with(size: 90.0, weight: .thin, traits: .monospacedNumbers),
|
||||||
@ -3142,7 +3182,7 @@ private final class ToolValueComponent: Component {
|
|||||||
self.addSubview(valueView)
|
self.addSubview(valueView)
|
||||||
}
|
}
|
||||||
transition.setPosition(view: valueView, position: valueFrame.center)
|
transition.setPosition(view: valueView, position: valueFrame.center)
|
||||||
transition.setBounds(view: valueView, bounds: CGRect(origin: .zero, size: valueFrame.size))
|
valueView.bounds = CGRect(origin: .zero, size: valueFrame.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let previousValue, component.value != previousValue, self.alpha > 0.0 {
|
if let previousValue, component.value != previousValue, self.alpha > 0.0 {
|
||||||
|
@ -29,6 +29,14 @@ private class VideoFrameLayer: SimpleShapeLayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class HandleView: UIImageView {
|
||||||
|
var hitTestSlop = UIEdgeInsets()
|
||||||
|
|
||||||
|
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
||||||
|
return self.bounds.inset(by: self.hitTestSlop).contains(point)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final class VideoScrubberComponent: Component {
|
final class VideoScrubberComponent: Component {
|
||||||
typealias EnvironmentType = Empty
|
typealias EnvironmentType = Empty
|
||||||
|
|
||||||
@ -93,10 +101,10 @@ final class VideoScrubberComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class View: UIView, UITextFieldDelegate {
|
final class View: UIView, UITextFieldDelegate {
|
||||||
private let leftHandleView = UIImageView()
|
private let leftHandleView = HandleView()
|
||||||
private let rightHandleView = UIImageView()
|
private let rightHandleView = HandleView()
|
||||||
private let borderView = UIImageView()
|
private let borderView = UIImageView()
|
||||||
private let cursorView = UIImageView()
|
private let cursorView = HandleView()
|
||||||
|
|
||||||
private let transparentFramesContainer = UIView()
|
private let transparentFramesContainer = UIView()
|
||||||
private let opaqueFramesContainer = UIView()
|
private let opaqueFramesContainer = UIView()
|
||||||
@ -144,14 +152,17 @@ final class VideoScrubberComponent: Component {
|
|||||||
self.leftHandleView.image = handleImage
|
self.leftHandleView.image = handleImage
|
||||||
self.leftHandleView.isUserInteractionEnabled = true
|
self.leftHandleView.isUserInteractionEnabled = true
|
||||||
self.leftHandleView.tintColor = .white
|
self.leftHandleView.tintColor = .white
|
||||||
|
self.leftHandleView.hitTestSlop = UIEdgeInsets(top: -8.0, left: -9.0, bottom: -8.0, right: -9.0)
|
||||||
|
|
||||||
self.rightHandleView.image = handleImage
|
self.rightHandleView.image = handleImage
|
||||||
self.rightHandleView.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
|
self.rightHandleView.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
|
||||||
self.rightHandleView.isUserInteractionEnabled = true
|
self.rightHandleView.isUserInteractionEnabled = true
|
||||||
self.rightHandleView.tintColor = .white
|
self.rightHandleView.tintColor = .white
|
||||||
|
self.rightHandleView.hitTestSlop = UIEdgeInsets(top: -8.0, left: -9.0, bottom: -8.0, right: -9.0)
|
||||||
|
|
||||||
self.cursorView.image = positionImage
|
self.cursorView.image = positionImage
|
||||||
self.cursorView.isUserInteractionEnabled = true
|
self.cursorView.isUserInteractionEnabled = true
|
||||||
|
self.cursorView.hitTestSlop = UIEdgeInsets(top: -8.0, left: -9.0, bottom: -8.0, right: -9.0)
|
||||||
|
|
||||||
self.borderView.image = generateImage(CGSize(width: 1.0, height: scrubberHeight), rotatedContext: { size, context in
|
self.borderView.image = generateImage(CGSize(width: 1.0, height: scrubberHeight), rotatedContext: { size, context in
|
||||||
context.clear(CGRect(origin: .zero, size: size))
|
context.clear(CGRect(origin: .zero, size: size))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user