BrownEye
BrownEye

Reputation: 979

Change ImagePicker from "Use Photo" to "Save Photo

I have a part in my app in which users can take a quick photo and save it to the camera roll. My only is that after the photo has been taken, it comes to the screen with the square cropper (i guess that's what it is) and then down the bottom it says "Retake" and "Use Photo". I want that Use Photo to say "Save Photo" (which is what it does anyway). Is there anyway to do this? Here's my code

- (IBAction)takePhoto:(UIButton *)sender {

UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;

[self presentViewController:picker animated:YES completion:NULL];
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

UIImage *chosenImage = info[UIImagePickerControllerEditedImage];
self.imageView.image = chosenImage;
UIImageWriteToSavedPhotosAlbum(chosenImage, nil, nil, nil);
[picker dismissViewControllerAnimated:YES completion:NULL];
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {

[picker dismissViewControllerAnimated:YES completion:NULL];
}

Upvotes: 1

Views: 2245

Answers (3)

Amadeu Cavalcante Filho
Amadeu Cavalcante Filho

Reputation: 2388

First swizzling Bundle

private func swizzle(_ bundle: Bundle.Type) {

    [(#selector(bundle.localizedString(forKey:value:table:)),
      #selector(bundle.rd_localizedString(forKey:value:table:)))]
        .forEach { original, swizzled in

            guard let originalMethod = class_getInstanceMethod(bundle, original),
                let swizzledMethod = class_getInstanceMethod(bundle, swizzled) else { return }

            let didAddMethod = class_addMethod(
                bundle,
                original,
                method_getImplementation(swizzledMethod),
                method_getTypeEncoding(swizzledMethod)
            )

            if didAddMethod {
                class_replaceMethod(
                    bundle,
                    swizzled,
                    method_getImplementation(originalMethod),
                    method_getTypeEncoding(originalMethod)
                )
            } else {
                method_exchangeImplementations(originalMethod, swizzledMethod)
            }
    }
}

private var hasSwizzled = false

extension Bundle {
    final public class func
        doBadSwizzleStuff() {
        guard !hasSwizzled else { return }

        hasSwizzled = true
        swizzle(self)

    }

    @objc internal func rd_localizedString(forKey: String, value: String?, table: String?) -> String {
        let bundle = Bundle.main
        return bundle.rd_localizedString(forKey: forKey, value: value, table: table)
    }
}

Second create localized strings for UIImagePickerController

Below content of mentioned files with keys I've seen (with standard english values), they are pretty self explaining

CameraUI.strings

"PHOTO" = "PHOTO";
"AEAF_LOCK_TEXT" = "AE/AF LOCK";
"API_CANCEL_TITLE" = "Cancel";
"HDR_AUTO" = "Auto";
"HDR_ON" = "On";
"HDR_OFF" = "Off";
"TIMER_OFF_TEXT" = "Off";
"USE_PHOTO" = "Use Photo";

PhotoLibraryServices.strings

"PHOTOS" = "Photos";
"CAMERA_ROLL" = "Camera roll";
"ALL_SCREENSHOTS" = "Screenshots";

PhotoLibrary.strings

"CANCEL" = "Cancel";
"RETAKE" = "Retake";
"STREAM_SHARED_BY_ME_SUBTITLE" = "From You";
"STREAM_SHARED_BY_SUBTITLE" = "From %@";
"ALBUM_IMAGE_COUNT_FORMAT" = "%@ Photos";
"ALBUM_VIDEO_COUNT_FORMAT" = "%@ Videos";
"1_ALBUM_PHOTO" = "1 Photo";
"1_ALBUM_VIDEO" = "1 Video";
"ALBUM_TWO_TYPES_LABEL_COMMAS" = "%@, %@";

PhotosUI.strings

"ALL_PHOTOS_IN_LIBRARY" = "Moments";
"PXUserCollectionsSectionTitle" = "My Albums";
"FULL_PHOTOS_GRID_ZOOM_LEVEL_TITLE" = "Moments";
"NO_PHOTOS_OR_VIDEOS" = "No Photos or Videos";

Third implement your localization class

internal enum L10n {
  internal enum CameraUI {
    /// AE/AF LOCK
    internal static let aeafLockText = L10n.tr("CameraUI", "AEAF_LOCK_TEXT")
    /// Cancel
    internal static let apiCancelTitle = L10n.tr("CameraUI", "API_CANCEL_TITLE")
    /// Auto
    internal static let hdrAuto = L10n.tr("CameraUI", "HDR_AUTO")
    /// Off
    internal static let hdrOff = L10n.tr("CameraUI", "HDR_OFF")
    /// On
    internal static let hdrOn = L10n.tr("CameraUI", "HDR_ON")
    /// PHOTO
    internal static let photo = L10n.tr("CameraUI", "PHOTO")
    /// Off
    internal static let timerOffText = L10n.tr("CameraUI", "TIMER_OFF_TEXT")
    /// Use test
    internal static let usePhoto = L10n.tr("CameraUI", "USE_PHOTO")
  }

    // MARK: - Implementation Details

extension L10n {
  private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
    // swiftlint:disable:next nslocalizedstring_key
    let format = NSLocalizedString(key, tableName: table, bundle: Bundle(for: BundleToken.self), comment: "")
    return String(format: format, locale: Locale.current, arguments: args)
  }
}

private final class BundleToken {}

Upvotes: 0

RevolAge company
RevolAge company

Reputation: 1

you can find this with recusrion way

func buttonWithTitle(forView view: UIView, title: String) -> UIButton? {
    guard view.subviews.count > 0 else { return nil }
    var needButton: UIButton? = nil
    for subview in view.subviews {
        if subview is UIButton {
            let button = subview as! UIButton
            if button.titleLabel?.text == title {
                return button
            }
        }

        needButton = buttonWithTitle(forView: subview, title: title)
        if needButton != nil { return needButton }
    }

    return needButton
}

Upvotes: 0

Ahmet Kazim Günay
Ahmet Kazim Günay

Reputation: 1062

U can change cancel button to any title u want:

  1. Add UINavigationControllerDelegate delegate to your viewController that u will click the button and will show the camera
  2. Add the below codes in your viewController:

    - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    
    [[UIApplication sharedApplication] setStatusBarHidden:YES];
    [self changeCancelToAnythingUWantOf:viewController andReplacementString:@"Your Replacement String"];
    

    }

    - (void)changeCancelToAnythingUWantOf:(UIViewController*)vc andReplacementString:(NSString*)title {
    
    for(UIView *subView in vc.view.subviews) {
     if ([subView isKindOfClass:[UIButton class]]) {
        UIButton *btn = (UIButton *)subView;
        if([btn.titleLabel.text isEqualToString:@"Cancel"]) {
            [btn setTitle:title forState:UIControlStateNormal];
            break;
        }
    }
    
     if (subView.subviews) {
        for (UIView *subSubView in subView.subviews) {
            if ([subSubView isKindOfClass:[UIButton class]]) {
                UIButton *btn = (UIButton *)subSubView;
                if([btn.titleLabel.text isEqualToString:@"Cancel"]) {
                    [btn setTitle:title forState:UIControlStateNormal];
                    break;
                } 
            }
    
            if (subSubView.subviews) {
                for (UIView *subSubSubView in subSubView.subviews) {
                    if ([subSubSubView isKindOfClass:[UIButton class]]) {
                        UIButton *btn = (UIButton *)subSubSubView;
                        if([btn.titleLabel.text isEqualToString:@"Cancel"]) {
                            [btn setTitle:title forState:UIControlStateNormal];
                            break;
                        } 
                    }
                }
             }
           }
         }
       }
     }
    

Upvotes: 3

Related Questions