iPhone UIButton - ตำแหน่งภาพ


116

ฉันมีUIButtonข้อความ "สำรวจแอป" และUIImage(>) Interface Builderดูเหมือนว่า:

[ (>) Explore the app ]

แต่ฉันต้องวางสิ่งนี้ไว้UIImageหลังข้อความ:

[ Explore the app (>) ]

ฉันจะย้ายUIImageไปทางขวาได้อย่างไร?


คุณสามารถใช้ Interface Builder ได้เช่นกัน ตรวจสอบคำตอบของฉันที่นี่: stackoverflow.com/questions/2765024/…
n8tr

1
เพียงใช้คลาสย่อยนี้กับโค้ดสองสามแถว: github.com/k06a/RTLButton
k06a

คำตอบ:


161

วิธีแก้ปัญหาของฉันค่อนข้างง่าย

[button sizeToFit];
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width);
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width);

4
ใช้งานได้ดีมาก! เป็นเรื่องยากที่จะเข้าใจแนวคิด edge inset มีความคิดว่าทำไมเราต้องตั้งค่าทั้งด้านซ้ายและด้านขวา? ในทางทฤษฎีถ้าฉันย้ายชื่อเรื่องไปทางซ้ายและภาพไปทางขวาก็เพียงพอแล้ว ทำไมต้องตั้งค่าทั้งซ้ายและขวา
PokerIncome.com

3
ทางออกที่ดีที่สุดที่ฉันพบ
Bimawa

2
คำตอบนี้ใช้ได้อย่างสมบูรณ์ คำตอบที่ยอมรับนั้นถูกต้องและชี้ไปที่เอกสาร API ที่ถูกต้อง แต่นี่คือโซลูชันการคัดลอกและวางเพื่อทำตามที่ OP ร้องขอ
mclaughlinj

กลายเป็นเรื่องที่ซับซ้อนเล็กน้อยเมื่อคุณเริ่มเปลี่ยนข้อความปุ่ม โซลูชันคลาสย่อยทำงานได้ดีกว่าสำหรับฉันในกรณีนี้
Brad Goss

ขอบคุณที่แสดงให้ฉันเห็นว่าคุณต้องใช้ความกว้างเท่ากันกับด้านซ้ายและด้านขวาฉันไม่เข้าใจ 100% ว่ามันทำงานอย่างไร (เพราะบางครั้งมันจะส่งผลต่อขนาดและที่มา) แต่ฉันสามารถแก้ปัญหาที่คล้ายกันได้ โดยใช้วิธีนี้
Toby

128

ในiOS 9เป็นต้นไปดูเหมือนว่าวิธีง่ายๆในการบรรลุเป้าหมายนี้คือการบังคับใช้ความหมายของมุมมอง

ใส่คำอธิบายภาพที่นี่

หรือโดยใช้โปรแกรมโดยใช้:

button.semanticContentAttribute = .ForceRightToLeft

4
เท่าที่ฉันชอบคำตอบของคุณ (+1) ฉันเกลียดที่จะบอกว่ามันอาจไม่ใช่วิธีที่ "เหมาะสม" ในการทำเช่นนี้ แต่ก็เป็นวิธีที่ง่ายที่สุดวิธีหนึ่ง
farzadshbfn

@farzadshbfn คุณพูดถูก ฉันเปลี่ยนคำนั้นเป็น "ง่าย" ดูเหมือนจะสอดคล้องกันมากขึ้น
Alvivi

@farzadshbfn ทำไมวิธีนี้จึงไม่ใช่วิธีที่ "เหมาะสม"?
Samman Bikram Thapa

3
@SammanBikramThapa IMHO วิธีที่เหมาะสมคือการ subclass UIButton และแทนที่ layoutSubviews และเคารพsemanticContentAttributeในตรรกะเค้าโครงของเราแทนที่จะเปลี่ยนตัวsemanticContentAttributeเอง (การเปลี่ยนวิธีการเชิงความหมายจะไม่ทำงานได้ดีกับความเป็นสากล)
farzadshbfn

@farzadshbfn ถูกต้องทั้งหมด ไม่ว่าคำตอบนี้จะให้คะแนนส่วนใหญ่ก็ไม่ถูกต้อง - อาจทำให้ UX สำหรับอินเทอร์เฟซจากขวาไปซ้ายแตก
Pavel Yakimenko

86

ตั้งค่าimageEdgeInsetและtitleEdgeInsetเพื่อย้ายส่วนประกอบรอบ ๆ ภายในภาพของคุณ คุณยังสามารถสร้างปุ่มโดยใช้กราฟิกที่มีขนาดเต็มและใช้เป็นภาพพื้นหลังของปุ่มได้ (จากนั้นใช้titleEdgeInsetsเพื่อเลื่อนชื่อไปรอบ ๆ )


8
การตั้งค่าอินเซ็ตนั้นน้อยกว่าการใช้ซับคลาส นี่คือจุดรวมของสิ่งที่ใส่เข้าไป การจัดการเฟรมสำหรับมุมมองย่อย (ที่คุณไม่ได้สร้างขึ้น) ให้ความรู้สึกเหมือนแฮ็ค
Kim André Sand

6
@kimsnarf จริงหรือ? มันทำงานน้อยกว่ามาก (และแฮ็กน้อยกว่า ) ในการปรับแต่งสิ่งที่ใส่เข้าไปเมื่อใดก็ตามที่คุณทำการเปลี่ยนแปลงเล็กน้อยในขนาดของภาพหรือความยาวของชื่อเรื่อง?
Kirk Woll

54

คำตอบของ Raymond W ดีที่สุดที่นี่ Subclass UIButton พร้อมเค้าโครงที่กำหนดเอง ง่ายมากที่จะทำนี่คือรูปแบบการใช้งาน Subviews ที่เหมาะกับฉัน:

- (void)layoutSubviews
{
    // Allow default layout, then adjust image and label positions
    [super layoutSubviews];

    UIImageView *imageView = [self imageView];
    UILabel *label = [self titleLabel];

    CGRect imageFrame = imageView.frame;
    CGRect labelFrame = label.frame;

    labelFrame.origin.x = imageFrame.origin.x;
    imageFrame.origin.x = labelFrame.origin.x + CGRectGetWidth(labelFrame);

    imageView.frame = imageFrame;
    label.frame = labelFrame;
}

2
วิธีนี้ดีกว่าในกรณีที่คุณต้องจัดการหลายปุ่ม แต่ฉันต้องเปลี่ยนเพียงปุ่มเดียว :)
Pavel Yakimenko

2
หากอิมเมจปุ่มเป็นศูนย์แสดงว่าผลลัพธ์ของป้ายกำกับไม่ถูกต้องอาจเป็นเพราะไม่ได้ใส่ UIImageView (ทดสอบบน iOS6.0) คุณควรพิจารณาแก้ไขเฟรมก็ต่อเมื่อ imageView.image ไม่ใช่ศูนย์
Scakko

2
ฉันขอแนะนำการปรับปรุงต่อไปนี้สำหรับคำตอบนี้เพื่อให้ทั้งสองมุมมองอยู่ตรงกลาง: 'CGFloat cumulativeWidth = CGRectGetWidth (imageFrame) + CGRectGetWidth (labelFrame) + 10; CGFloat tooWidth = CGRectGetWidth (self.bounds) - cumulativeWidth; labelFrame.origin.x = tooWidth / 2; imageFrame.origin.x = CGRectGetMaxX (labelFrame) + 10; '
i-konov

สิ่งนี้หยุดพักบน iOS 7 สำหรับฉัน ใครอีกไหม? ทำงานได้ดีบน iOS 8
rounak

1
ไม่รองรับ iOS7 เลยและปัญหาของคุณจะหมดไป คุณไม่ควร supoprt อยู่ดี
Gil Sand

30

สิ่งที่เกี่ยวกับคลาสย่อยUIButtonและการลบล้างlayoutSubviews?

จากนั้นประมวลผลสถานที่ของself.imageView&self.titleLabel


4
วิธีนี้ง่ายกว่าคำแนะนำอื่น ๆ ทั้งหมด (เช่นเดียวกับด้านบน) เกี่ยวกับการพยายามวางทุกอย่างให้ถูกต้องโดยใช้อินเซ็ตที่ปรับแต่งด้วยมือ
Steven Kramer

13

อีกวิธีง่ายๆ (ที่ไม่ใช่ iOS 9 เท่านั้น) คือซับคลาส UIButton เพื่อแทนที่สองวิธีนี้

override func titleRectForContentRect(contentRect: CGRect) -> CGRect {
    var rect = super.titleRectForContentRect(contentRect)
    rect.origin.x = 0
    return rect
}

override func imageRectForContentRect(contentRect: CGRect) -> CGRect {
    var rect = super.imageRectForContentRect(contentRect)
    rect.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(rect)
    return rect
}

contentEdgeInsets ถูกนำมาพิจารณาโดยใช้ super


ขอบคุณ! ฉันชอบสิ่งนี้มากกว่าคำตอบที่คลาสย่อยและการแทนที่เค้าโครง Subviews () :)
Joe Susnick

1
วิธีที่ดีที่สุดในการพูดถึงเรื่องนี้ในความเห็นที่ต่ำต้อยของฉัน :)
DrPatience

9

การบังคับให้ "ขวาไปซ้าย" สำหรับปุ่มไม่ใช่ตัวเลือกหากแอปของคุณรองรับทั้ง "ซ้ายไปขวา" และ "ขวาไปซ้าย"

วิธีแก้ปัญหาที่เหมาะกับฉันคือคลาสย่อยที่สามารถเพิ่มลงในปุ่มใน Storyboard และทำงานได้ดีกับข้อ จำกัด (ทดสอบใน iOS 11):

class ButtonWithImageAtEnd: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()

        if let imageView = imageView, let titleLabel = titleLabel {
            let padding: CGFloat = 15
            imageEdgeInsets = UIEdgeInsets(top: 5, left: titleLabel.frame.size.width+padding, bottom: 5, right: -titleLabel.frame.size.width-padding)
            titleEdgeInsets = UIEdgeInsets(top: 0, left: -imageView.frame.width, bottom: 0, right: imageView.frame.width)
        }

    }

}

โดยที่ "padding" จะเป็นช่องว่างระหว่างชื่อเรื่องและรูปภาพ


แน่นอนว่า.forceRightToLeftเป็นตัวเลือก! เพียงแค่ใช้ค่าตรงข้าม ( .forceLeftToRight) UIApplication.shared.userInterfaceLayoutDirection == .rightToLeftถ้า
manmal

5

ใน Swift:

override func layoutSubviews(){
    super.layoutSubviews()

    let inset: CGFloat = 5

    if var imageFrame = self.imageView?.frame,
       var labelFrame = self.titleLabel?.frame {

       let cumulativeWidth = imageFrame.width + labelFrame.width + inset
       let excessiveWidth = self.bounds.width - cumulativeWidth
       labelFrame.origin.x = excessiveWidth / 2
       imageFrame.origin.x = labelFrame.origin.x + labelFrame.width + inset

       self.imageView?.frame = imageFrame
       self.titleLabel?.frame = labelFrame  
    }
}

4

สร้างคำตอบโดย @split ...

คำตอบนั้นยอดเยี่ยมมาก แต่จะไม่สนใจข้อเท็จจริงที่ว่าปุ่มอาจมีภาพที่กำหนดเองและการตั้งค่าขอบหัวเรื่องที่กำหนดไว้ล่วงหน้า (เช่นในสตอรีบอร์ด)

ตัวอย่างเช่นคุณอาจต้องการให้รูปภาพมีช่องว่างจากด้านบนและด้านล่างของคอนเทนเนอร์ แต่ยังคงย้ายรูปภาพไปทางด้านขวาของปุ่ม

ฉันขยายแนวคิดด้วยวิธีนี้: -

- (void) moveImageToRightSide {
    [self sizeToFit];

    CGFloat titleWidth = self.titleLabel.frame.size.width;
    CGFloat imageWidth = self.imageView.frame.size.width;
    CGFloat gapWidth = self.frame.size.width - titleWidth - imageWidth;
    self.titleEdgeInsets = UIEdgeInsetsMake(self.titleEdgeInsets.top,
                                            -imageWidth + self.titleEdgeInsets.left,
                                            self.titleEdgeInsets.bottom,
                                            imageWidth - self.titleEdgeInsets.right);

    self.imageEdgeInsets = UIEdgeInsetsMake(self.imageEdgeInsets.top,
                                            titleWidth + self.imageEdgeInsets.left + gapWidth,
                                            self.imageEdgeInsets.bottom,
                                            -titleWidth + self.imageEdgeInsets.right - gapWidth);
}

2
// Get the size of the text and image
CGSize buttonLabelSize = [[self.button titleForState:UIControlStateNormal] sizeWithFont:self.button.titleLabel.font];
CGSize buttonImageSize = [[self.button imageForState:UIControlStateNormal] size];

// You can do this line in the xib too:
self.button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

// Adjust Edge Insets according to the above measurement. The +2 adds a little space 
self.button.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -(buttonLabelSize.width+2));
self.button.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, buttonImageSize.width+2);

สิ่งนี้จะสร้างปุ่มที่จัดชิดขวาดังนี้:

[           button label (>)]

ปุ่มไม่ได้ปรับความกว้างตามบริบทดังนั้นช่องว่างจะปรากฏทางด้านซ้ายของป้ายกำกับ คุณสามารถแก้ปัญหานี้ได้โดยคำนวณความกว้างเฟรมของปุ่มจาก buttonLabelSize.width และ buttonImageSize.width



0

โซลูชันนี้ใช้ได้กับ iOS 7 ขึ้นไป

เพียง UIButton คลาสย่อย

@interface UIButton (Image)

- (void)swapTextWithImage;

@end

@implementation UIButton (Image)

- (void)swapTextWithImage {
   const CGFloat kDefaultPadding = 6.0f;
   CGSize buttonSize = [self.titleLabel.text sizeWithAttributes:@{
                                                               NSFontAttributeName:self.titleLabel.font
                                                               }];

   self.titleEdgeInsets = UIEdgeInsetsMake(0, -self.imageView.frame.size.width, 0, self.imageView.frame.size.width);
   self.imageEdgeInsets = UIEdgeInsetsMake(0, buttonSize.width + kDefaultPadding, 0, -buttonSize.width); 
}

@end

การใช้งาน (ที่ไหนสักแห่งในชั้นเรียนของคุณ):

[self.myButton setTitle:@"Any text" forState:UIControlStateNormal];
[self.myButton swapTextWithImage];

0

สร้างจากคำตอบก่อนหน้านี้ หากคุณต้องการให้มีระยะขอบระหว่างไอคอนและชื่อของปุ่มรหัสจะต้องเปลี่ยนแปลงเล็กน้อยเพื่อป้องกันไม่ให้ป้ายกำกับและไอคอนลอยอยู่เหนือขอบเขตของปุ่มที่มีขนาดภายใน

let margin = CGFloat(4.0)
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width);
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width)
button.contentEdgeInsets = UIEdgeInsetsMake(0, margin, 0, margin)

บรรทัดรหัสสุดท้ายมีความสำคัญสำหรับการคำนวณขนาดเนื้อหาภายในสำหรับโครงร่างอัตโนมัติ


0

นี่คือวิธีของฉันเองในการทำสิ่งนั้น(หลังจากนั้นประมาณ 10 ปี)

  1. คลาสย่อยจาก UIButton (ปุ่มที่เราอาศัยอยู่ในยุค Swift)
  2. ใส่รูปภาพและป้ายกำกับในมุมมองแบบเรียงซ้อน
class CustomButton: Button {

    var didLayout: Bool = false // The code must be called only once

    override func layoutSubviews() {
        super.layoutSubviews()
        if !didLayout, let imageView = imageView, let titleLabel = titleLabel {
            didLayout = true
            let stack = UIStackView(arrangedSubviews: [titleLabel, imageView])
            addSubview(stack)
            stack.edgesToSuperview() // I use TinyConstraints library. You could handle the constraints directly
            stack.axis = .horizontal
        }
    }
}

0

โซลูชันบรรทัดเดียวใน Swift:

// iOS 9 and Onwards
button.semanticContentAttribute = .forceRightToLeft

มันไม่ดีเพราะจะทำลายเค้าโครงสำหรับผู้ใช้ RTL ทั้งหมด คุณจะต้องบังคับจากซ้ายไปขวาสำหรับพวกเขา คุณควรลองวิธีแก้ปัญหาอื่น ๆ จากที่นี่
Pavel Yakimenko
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.