2

Can you help me how I can customize cancel and post buttons in SLComposeServiceViewController?

I want to change title and button image.

juve100
  • 33
  • 6

3 Answers3

3

SLComposeServiceViewController has very limited options for customizing its UI, and this does not currently include the ability to modify the "cancel" and "post" buttons. In the current version of iOS, the only way to avoid using those buttons is to not use SLComposeServiceViewController. Share extensions are not required to use that class and may use a fully custom UI. If those buttons are not appropriate, that's your only option.

Tom Harrington
  • 69,312
  • 10
  • 146
  • 170
1

I came up with this solution. Worst case scenario Apple changes things up and stops using a navigation bar, in which case the buttons will simply revert back to saying 'Post' and 'Cancel'. There should be no crashes.

For this example, I've used an '✖' for cancel and '✔' for post.

- (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    // find the navigation bar
    UINavigationBar* bar = self.navigationController.navigationBar;
    if (bar == nil)
    {
        for (UIView* b in self.view.subviews)
        {
            if ([b isKindOfClass:UINavigationBar.class])
            {
                bar = (UINavigationBar*)b;
                break;
            }
        }
        if (bar == nil)
        {
            return;
        }
    }

    // find the cancel and post buttons, assuming the post button is on the far right which is a common iOS UI design, to put the positive or confirm action on the right
    // also deals with right to left languages (which SLComposeViewController does not support yet), where the post button will be on the left
    UIButton* postButton = nil;
    UIButton* cancelButton = nil;
    BOOL rightToLeft = NO;
    if ([UIView.class respondsToSelector:@selector(userInterfaceLayoutDirectionForSemanticContentAttribute:)])
    {
        rightToLeft = ([UIView userInterfaceLayoutDirectionForSemanticContentAttribute:bar.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft);
    }
    CGFloat x = (rightToLeft ? FLT_MAX : FLT_MIN);
    for (UIView* v in bar.subviews)
    {
        if ([v isKindOfClass:UIButton.class] && ((rightToLeft && v.frame.origin.x < x) || (!rightToLeft && v.frame.origin.x > x)))
        {
            x = v.frame.origin.x;
            if (postButton != nil)
            {
                cancelButton = postButton;
            }
            postButton = (UIButton*)v;
        }
    }

    // if we found a cancel UIButton, set the title
    if (cancelButton != nil)
    {
        [cancelButton setTitle:@"✖" forState:UIControlStateNormal];
    }

    // if we found a post UIButton, set the title
    if (postButton != nil)
    {
        [postButton setTitle:@"✔" forState:UIControlStateNormal];
    }
}
jjxtra
  • 20,415
  • 16
  • 100
  • 140
-1

I just found a way to do it:

class CustomServiceViewController: SLComposeServiceViewController {
    override func viewDidLoad() {
        let navigationBar = view.subviews.first?.subviews?.last? as? UINavigationBar
        let postButton = navigationBar?.subviews.last? as? UIButton
        let cancelButton = navigationBar?.subviews.last? as? UIButton
        postButton?.setTitle("Done", forState: .Normal)
    }
}

Be warned - it's a fragile solution, based on undocumented internals of SLComposeServiceViewController

average Joe
  • 4,377
  • 2
  • 25
  • 23