Richard Topchii
Richard Topchii

Reputation: 8165

Change TintColor of UIImagePickerController

I've set a global tintColor in my app by calling:

UIView.appearance().tintColor = myColor

However, the same color applies to the UIImagePickerController and only some of the UI elements are colored: For example, the sun icon has a custom tintColor while the focus frame has the default one.

How is it possible not to apply a global appearance configuration to the UIImagePickerController?

enter image description here

My proposed solution doesn't fully address the issue, since the inputAccessoryView still has its own tintColor:

window?.tintColor = myColor

Update:

I configure the application-wide tintcolor on launch:

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    configureWindowAndInitialViewController()
    UIView.appearance().tintColor = .cyan // Setting a global tintColor
    return true
  }

Then, I show an UIImagePickerController:

  func presentPhotoPicker(sourceType: UIImagePickerController.SourceType) {
    if let mediaTypes = UIImagePickerController.availableMediaTypes(for: sourceType)?
      .filter({$0 == kUTTypeImage as String}),
      !mediaTypes.isEmpty {
      let picker = UIImagePickerController()
      picker.delegate = self
      picker.mediaTypes = mediaTypes
      picker.sourceType = sourceType
      picker.allowsEditing = true
      controller?.present(picker, animated: true, completion: nil)
    }
  }

Input accessory view:

To add an input accessory view, first of all, a textField should be created. Then it is possible to just attach a toolbar to the Textfield:

let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: sefl.view, action: #selector(UIView.endEditing))
items.append(contentsOf: [spacer, doneButton])

toolbar.setItems(items, animated: false)
textField.inputAccessoryView = toolbar

enter image description here

Upvotes: 4

Views: 2584

Answers (3)

AD Progress
AD Progress

Reputation: 5076

I believe that this is what you are looking for try this and tweak to your likes:

let myImagePicker = UIImagePickerController()
myImagePicker.navigationBar.translucent = false
myImagePicker.navigationBar.barTintColor = .blueColor() // Background color
myImagePicker.navigationBar.tintColor = .whiteColor() // Cancel button ~ any UITabBarButton items
myImagePicker.navigationBar.titleTextAttributes = [
        NSForegroundColorAttributeName : UIColor.whiteColor()
] // Title color

this is all I found:

Customizing the Camera Controls

var showsCameraControls: Bool

Indicates whether the image picker displays the default camera controls.

var cameraOverlayView: UIView?

The view to display on top of the default image picker interface.

var cameraViewTransform: CGAffineTransform

The transform to apply to the camera’s preview image. Capturing Still Images or Movies

func takePicture()

Captures a still image using the camera.

func startVideoCapture()

Starts video capture using the camera specified by the UIImagePickerControllerCameraDevice property.

func stopVideoCapture()

Stops video capture.

Configuring the Camera to Use

class func isCameraDeviceAvailable(UIImagePickerControllerCameraDevice)

Returns a Boolean value that indicates whether a given camera is available.

var cameraDevice: UIImagePickerControllerCameraDevice

The camera used by the image picker controller.

enum UIImagePickerControllerCameraDevice

The camera to use for image or movie capture. Configuring the Camera Capture Mode

class func availableCaptureModes(for: UIImagePickerControllerCameraDevice)

Returns an array of NSNumber objects indicating the capture modes supported by a given camera device.

var cameraCaptureMode: UIImagePickerControllerCameraCaptureMode

The capture mode used by the camera.

enum UIImagePickerControllerCameraCaptureMode

The category of media for the camera to capture.

Configuring the Flash Behavior

class func isFlashAvailable(for: UIImagePickerControllerCameraDevice)

Indicates whether a given camera has flash illumination capability.

var cameraFlashMode: UIImagePickerControllerCameraFlashMode

The flash mode used by the active camera.

enum UIImagePickerControllerCameraFlashMode

The flash mode to use with the active camera.

Configuring the Export Presets

var imageExportPreset: UIImagePickerControllerImageURLExportPreset

The preset to use when preparing images for export to your app.

enum UIImagePickerControllerImageURLExportPreset

Constants indicating how to export images to the client app.

var videoExportPreset: String

The preset to use when preparing video for export to your app.

I have dug thru the documentation and did not found a way of changing the focus view. Perhaps apple does not let you to do that. Maybe there is a custom PickerView framework on cocoapods or a custom camera framework.

Upvotes: 0

trungduc
trungduc

Reputation: 12144

After you change window?.tintColor, inputAccessoryView.tintColor isn't changed because inputAccessoryView isn't a subview of current window (they don't have same view’s hierarchy) so window.tintColor won't affect inputAccessoryView.

To resolve problem, I suggest to use NotificationCenter to observe and change window.tintColor each time a new UIWindow becomes visible. You can put the code inside AppDelegate

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
  // Override point for customization after application launch.
  NotificationCenter.default.addObserver(self, selector: #selector(self.windowDidBecomeVisible), name: .UIWindowDidBecomeVisible, object: nil)
  return true
}

@objc func windowDidBecomeVisible(notification: NSNotification) {
  // Each time an `UIWindow` becomes visible, change its |tintColor|
  let visibleWindow = notification.object as! UIWindow
  visibleWindow.tintColor = .red
}

If you want to change tintColor only for the UIImagePickerController, you need to change tintColor for every view which is displayed on UIImagePickerController.

  1. Define an extension to change all subview's tintColor.

    extension UIView {
      func changeTintColor(color: UIColor) -> Void {
        for view in subviews{
          view.tintColor = color
          view.changeTintColor(color: color);
        }
      }
    }
    
  2. Use UINavigationControllerDelegate to get UIViewController which is displayed on UIImagePickerView. Change view's tintColor inside this controller

    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
      viewController.view.changeTintColor(color: .red)
    }
    
  3. Don't forget to set UIImagePickerController's delegate to self.

Upvotes: 4

Richard Topchii
Richard Topchii

Reputation: 8165

Fixed by setting the global tintColor on Window instead of the UIAppearance proxy:

window?.tintColor = myColor

Upvotes: 2

Related Questions