ইমেজআইজনেটস এবং শিরোনামএডিজইনসেটস সহ UIButton এ পাঠ্য এবং চিত্র প্রান্তিককরণ


247

আমি পাঠ্য দুটি লাইনের বামদিকে একটি আইকন রাখতে চাই যে চিত্র এবং পাঠ্য শুরুর মধ্যে প্রায় 2-3 পিক্সেল স্থান রয়েছে। নিয়ন্ত্রণ নিজেই কেন্দ্র অনুভূমিকভাবে প্রান্তিক করা হয় (ইন্টারফেস বিল্ডারের মাধ্যমে সেট)

বোতামটি এর মতো কিছু হতে পারে:

|                  |
|[Image] Add To    |
|        Favorites |

আমি এটিকে কনটেন্ট এডজেসনেট, ইমেজএডজিনসেটস এবং শিরোনামএডজিনসেটস দিয়ে কোনও কনফিগার করার চেষ্টা করছি। আমি বুঝতে পারি যে aণাত্মক মানটি প্রান্তকে প্রসারিত করে যখন একটি ধনাত্মক মান একে সঙ্কুচিত করে এটি কেন্দ্রের কাছাকাছি যেতে।

আমি চেষ্টা করেছিলাম:

[button setTitleEdgeInsets:UIEdgeInsetsMake(0, -image.size.width, 0, 0)];
[button setImageEdgeInsets:UIEdgeInsetsMake(0, button.titleLabel.bounds.size.width, 0, 0)];

তবে এটি সঠিকভাবে প্রদর্শন করে না। আমি মানগুলি টুইট করছি তবে বাম ইনসেট মানটিতে -5 থেকে -10 বলার সময় এটি প্রত্যাশিত পদ্ধতিতে স্থানান্তরিত হবে না বলে মনে হয়। -10 পাঠ্যটি পুরো বাম দিকে স্কুট করবে তাই আমি প্রত্যাশা করছিলাম যে -5 বাম দিক থেকে এটি অর্ধেক পথ স্কুট করবে তবে তা হয় না।

পোকামাকড় পিছনে যুক্তি কি? আমি চিত্র স্থাপন এবং সম্পর্কিত পরিভাষার সাথে পরিচিত নই।

আমি এই SO প্রশ্নটিকে একটি রেফারেন্স হিসাবে ব্যবহার করেছি তবে আমার মান সম্পর্কে কিছু সঠিক নয়। ইউআইবাটন: ইমেজএডজেইনেসেটস এবং শিরোনামএডজিনসেটস ব্যবহার করে একটি চিত্র এবং পাঠ্যকে কীভাবে কেন্দ্র করবেন?

উত্তর:


391

আমি ডকুমেন্টেশনটির সাথে সম্মত হই imageEdgeInsetsএবং titleEdgeInsetsআরও ভাল হওয়া উচিত, তবে আমি পরীক্ষার এবং ত্রুটির অবলম্বন না করে কীভাবে সঠিক পজিশনিং পেতে পারি তা বুঝতে পেরেছি।

সাধারণ ধারণাটি এই প্রশ্নের এখানে রয়েছে তবে আপনি যদি পাঠ্য এবং চিত্র উভয়ই কেন্দ্রিক করতে চান তবে তা ছিল। আমরা চাই না যে চিত্র এবং পাঠ্যটি পৃথকভাবে কেন্দ্রীভূত হোক, আমরা চাই চিত্র এবং পাঠ্যটি একক সত্তা হিসাবে একসাথে কেন্দ্রীভূত হোক। এটি আসলে ইউআইবাটন যা ইতিমধ্যে করেছে তাই আমাদের কেবল ব্যবধানটি সামঞ্জস্য করতে হবে।

CGFloat spacing = 10; // the amount of spacing to appear between image and title
tabBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
tabBtn.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);

আমি এটিকে ইউআইবুটনের একটি বিভাগেও পরিণত করেছি যাতে এটি ব্যবহার করা সহজ হবে:

UIButton + + Position.h

@interface UIButton(ImageTitleCentering)

-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing;

@end

UIButton + + Position.m

@implementation UIButton(ImageTitleCentering)

-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing {
    self.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
    self.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);
}

@end

সুতরাং এখন আমাকে যা করতে হবে তা হ'ল:

[button centerButtonAndImageWithSpacing:10];

এবং প্রতিবার আমার যা প্রয়োজন তা আমি পেয়েছি। প্রান্তের পোকামাকড়ের সাথে ম্যানুয়ালি আর গোলযোগ নেই।

সম্পাদনা: চিত্র এবং পাঠ্য অদলবদল

মন্তব্যে @ জাভালের জবাব

এই একই প্রক্রিয়াটি ব্যবহার করে আমরা চিত্র এবং পাঠ্যটি অদলবদল করতে পারি। অদলবদল সম্পাদন করতে, কেবল একটি নেতিবাচক ব্যবধান ব্যবহার করুন তবে পাঠ্য এবং চিত্রের প্রস্থও অন্তর্ভুক্ত করুন। এর জন্য ফ্রেমগুলি জানা এবং লেআউট ইতিমধ্যে সম্পাদন করা প্রয়োজন।

[self.view layoutIfNeeded];
CGFloat flippedSpacing = -(desiredSpacing + button.currentImage.size.width + button.titleLabel.frame.size.width);
[button centerButtonAndImageWithSpacing:flippedSpacing];

অবশ্যই আপনি সম্ভবত এটির জন্য একটি দুর্দান্ত পদ্ধতি তৈরি করতে চাইবেন, সম্ভাব্যভাবে দ্বিতীয় বিভাগের পদ্ধতি যুক্ত করুন, এটি পাঠকের অনুশীলন হিসাবে ছেড়ে দেওয়া হবে।


যদি আমার স্বাভাবিক এবং হাইলাইটের জন্য আলাদা আলাদা শিরোনাম থাকে, যখন ব্যবহারকারী বাটনটি হাইলাইট করে এবং আন-হাইলাইট করে আমি কীভাবে এটি পুনরায় কেন্দ্র করতে পারি?
ব্যবহারকারী 102008

@ ব্যবহারকারী 102008 সম্পূর্ণ আলাদা আলাদা শিরোনাম? নাকি শুধু ভিন্ন রঙ? আপনি যদি ব্যবহার করছেন [UIButton setTitleColor:forState:]বা এমনকি ব্যবহার করছেন তবে অবস্থান পরিবর্তন করা উচিত নয় [UIButton setTitle:forState:]
কেকোয়া

5
আপনি কীভাবে [বোতামের আকারটিফিট] ঠিক করবেন যাতে এটি সঠিকভাবে মাপ দেয়?
রনলগ

@ রনলগ আপনি কেন সাইজ টোফিটের প্রয়োজন তা আমি নিশ্চিত নই, তাই আমি আপনার প্রশ্নের উত্তর দিতে পারি না। সাইজটোফিট ব্যবহার না করে এটি আমার পক্ষে ভাল কাজ করে।
কেকোয়া

আমার সাইজটিফিটের প্রয়োজন কারণ বোতামগুলি / পাঠ্য গতিশীল, সুতরাং (ব্যবহারকারীর সংজ্ঞায়িত) লেবেলটি ফিট করার জন্য আমার বোতামটি আকার করতে হবে। সমস্যাটি হ'ল এটি যুক্ত হওয়া জায়গার জন্য ক্ষতিপূরণ দেয় না। আমি এটিকে ওভাররাইড করে দিয়েছিলাম এবং ম্যানুয়ালি ফ্রেমের প্রস্থটি 10 ​​দ্বারা বাড়িয়েছি
রনলগ

394

আমি এই পার্টিতে কিছুটা দেরি করেছি, তবে আমার কাছে যুক্ত করার মতো কিছু দরকারী আছে বলে আমি মনে করি।

কেকোয়ার উত্তর দুর্দান্ত তবে রনলগের উল্লেখ অনুসারে, এটি বোতামটিকে আর সম্মান sizeToFitকরতে পারে না বা আরও গুরুত্বপূর্ণ, এটি অভ্যন্তরীণ আকারের হয়ে গেলে বোতামটি তার সামগ্রীটি ক্লিপ করতে পারে। বাবা!

প্রথম, যদিও,

আমি কীভাবে বিশ্বাস করি imageEdgeInsetsএবং কীভাবে titleEdgeInsetsকাজ করি তার একটি সংক্ষিপ্ত বিবরণ :

এর জন্য দস্তাবেজimageEdgeInsets অংশে নিম্নলিখিত বলার আছে:

বোতামের চিত্রের জন্য কার্যকর অঙ্কন আয়তক্ষেত্রটি পুনরায় আকার দিতে এবং পুনরায় স্থাপন করতে এই সম্পত্তিটি ব্যবহার করুন। আপনি চারটি ইনসেটের (উপরে, বাম, নীচে, ডানদিকে) আলাদা আলাদা মান নির্দিষ্ট করতে পারবেন। একটি ধনাত্মক মান সঙ্কুচিত হয়, বা পোকামাকড়, যে প্রান্তটি it এটিকে বোতামের কেন্দ্রের নিকটে চলে যায়। একটি নেতিবাচক মান প্রসারিত হয়, বা আউটসেটগুলি, যে প্রান্তটি।

আমি বিশ্বাস করি যে এই ডকুমেন্টেশনটি কল্পনা করেই লেখা হয়েছিল যে বোতামটির কোনও শিরোনাম নেই, কেবল একটি চিত্র। এটি এইভাবে অনেক বেশি ধারণা দেয় এবং UIEdgeInsetsসাধারণত কীভাবে আচরণ করে তা আচরণ করে । মূলত, ইমেজের ফ্রেমটি (বা শিরোনাম, সহ titleEdgeInsets) ইতিবাচক ইনসেটের জন্য এবং নেতিবাচক পোকামাকড়গুলির জন্য বাইরের দিকে সরানো হয়।

ঠিক আছে, তাই কি?

আমি সেখানে যাচ্ছি! আপনার একটি ডিফল্টরূপে যা আছে তা এখানে একটি চিত্র এবং একটি শিরোনাম সেট করে (বোতামের সীমানাটি যেখানে রয়েছে তা দেখানোর জন্য সবুজ)):

সূচনা চিত্র;  শিরোনাম এবং চিত্রের মধ্যে কোনও স্থান নেই।

আপনি যখন কোনও চিত্র এবং শিরোনামের মধ্যে ফাঁক করে দিতে চান, উভয়ই ক্রাশ হওয়ার কারণ না রেখে, আপনাকে চারটি আলাদা আলাদা ইনসেট স্থাপন করতে হবে, প্রতিটি চিত্র এবং শিরোনামের জন্য দুটি সেট করতে হবে। এর কারণ আপনি এই উপাদানগুলির ফ্রেমের আকারগুলি পরিবর্তন করতে চান না , কেবল তাদের অবস্থানগুলি। আপনি যখন এইভাবে চিন্তা শুরু করেন, কেকোয়ার দুর্দান্ত বিভাগে প্রয়োজনীয় পরিবর্তনটি স্পষ্ট হয়ে ওঠে:

@implementation UIButton(ImageTitleCentering)

- (void)centerButtonAndImageWithSpacing:(CGFloat)spacing {
    CGFloat insetAmount = spacing / 2.0;
    self.imageEdgeInsets = UIEdgeInsetsMake(0, -insetAmount, 0, insetAmount);
    self.titleEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, -insetAmount);
}

@end

তবে অপেক্ষা করুন , আপনি বলবেন, আমি যখন এটি করি তখন আমি এটি পাই:

ব্যবধানটি ভাল, তবে চিত্র এবং শিরোনাম দেখার ফ্রেমের বাইরে।

ও আচ্ছা! আমি ভুলে গেছি, ডক্স আমাকে এ সম্পর্কে সতর্ক করেছে। তারা বলে, অংশে:

এই বৈশিষ্ট্যটি কেবল বিন্যাসের সময় চিত্রের অবস্থানের জন্য ব্যবহৃত হয়। বোতামটি এই সম্পত্তিটি নির্ধারণ করতে intrinsicContentSizeএবং ব্যবহার করে না sizeThatFits:

কিন্তু হয় একটি সম্পত্তি যে করতে পারেন সাহায্য, এবং যে এর contentEdgeInsetsএর জন্য দস্তাবেজগুলি অংশ হিসাবে বলে:

বোতামটি এই সম্পত্তিটি নির্ধারণ করতে intrinsicContentSizeএবং ব্যবহার করে sizeThatFits:

ভাল লাগছে। সুতরাং আরও একবার এই বিভাগটি টুইট:

@implementation UIButton(ImageTitleCentering)

- (void)centerButtonAndImageWithSpacing:(CGFloat)spacing {
    CGFloat insetAmount = spacing / 2.0;
    self.imageEdgeInsets = UIEdgeInsetsMake(0, -insetAmount, 0, insetAmount);
    self.titleEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, -insetAmount);
    self.contentEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, insetAmount);
}

@end

এবং আপনি কি পেতে পারি?

ব্যবধান এবং ফ্রেম এখন সঠিক।

আমার কাছে বিজয়ী মনে হচ্ছে।


সুইফটে কাজ করছেন এবং আদৌ কোনও চিন্তাভাবনা করতে চান না? সুইফটে এক্সটেনশনের চূড়ান্ত সংস্করণটি এখানে:

extension UIButton {
    func centerTextAndImage(spacing: CGFloat) {
        let insetAmount = spacing / 2
        imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount, bottom: 0, right: insetAmount)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: -insetAmount)
        contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
    }
}

25
কি দুর্দান্ত উত্তর! হ্যাঁ পার্টিতে কয়েক বছর দেরি হয়ে গেছে তবে এটি intrinsicContentSizeভুল হওয়ার বিষয়টি সমাধান করেছে , যা মূল উত্তরটি গৃহীত হওয়ার পরে এই স্বয়ংক্রিয় বিন্যাসের দিনগুলিতে খুব গুরুত্বপূর্ণ।
Acey

2
এবং যদি আপনি বোতাম এবং চিত্র এবং লেবেলের বাইরের অংশের মধ্যে একই পরিমাণের ব্যবধান চান, তবে spacingস্বতঃসংশ্লিষ্ট এডজিনসেটস এর চারটি মানের প্রতিটিটিতে যুক্ত করুন:self.contentEdgeInsets = UIEdgeInsetsMake(spacing, spacing + insetAmount, spacing, spacing + insetAmount);
এরিক ভ্যান ডের নিউট

1
দুর্দান্ত উত্তর, দুঃখের বিষয় চিত্রটি সঠিকভাবে সাজানো থাকলে এবং পাঠ্যের দৈর্ঘ্য পৃথক হতে পারে তখন এটি বেশ ভালভাবে কাজ করে না।
jlpiedrahita

2
প্রায় নিখুঁত উত্তর! কেবল অনুপস্থিত জিনিসটি হ'ল চিত্র এবং শিরোনামের ইনসেটগুলি ডান থেকে বাম ইন্টারফেসে চলাকালীন উল্টানো উচিত।
jeeeyul

1 থেকে 1 এ কীভাবে চিত্র অনুপাত সেট করবেন
ইয়েস্টে মুরাতভ

39

ইন্টারফেস বিল্ডারে। UIButton -> বৈশিষ্ট্য পরিদর্শক -> এজ = শিরোনামটি নির্বাচন করুন এবং প্রান্তের ইনসেটগুলি সংশোধন করুন


38

এছাড়াও আপনি কিছু অনুরূপ করতে চান

এখানে চিত্র বর্ণনা লিখুন

তোমার দরকার

1. বোতামের জন্য অনুভূমিক এবং উল্লম্ব সারিবদ্ধতা সেট করুন

এখানে চিত্র বর্ণনা লিখুন

  1. সমস্ত প্রয়োজনীয় মান এবং সেট সন্ধান করুন UIImageEdgeInsets

            CGSize buttonSize = button.frame.size;
            NSString *buttonTitle = button.titleLabel.text;
            CGSize titleSize = [buttonTitle sizeWithAttributes:@{ NSFontAttributeName : [UIFont camFontZonaProBoldWithSize:12.f] }];
            UIImage *buttonImage = button.imageView.image;
            CGSize buttonImageSize = buttonImage.size;
    
            CGFloat offsetBetweenImageAndText = 10; //vertical space between image and text
    
            [button setImageEdgeInsets:UIEdgeInsetsMake((buttonSize.height - (titleSize.height + buttonImageSize.height)) / 2 - offsetBetweenImageAndText,
                                                        (buttonSize.width - buttonImageSize.width) / 2,
                                                        0,0)];                
            [button setTitleEdgeInsets:UIEdgeInsetsMake((buttonSize.height - (titleSize.height + buttonImageSize.height)) / 2 + buttonImageSize.height + offsetBetweenImageAndText,
                                                        titleSize.width + [button imageEdgeInsets].left > buttonSize.width ? -buttonImage.size.width  +  (buttonSize.width - titleSize.width) / 2 : (buttonSize.width - titleSize.width) / 2 - buttonImage.size.width,
                                                        0,0)];

এটি বোতামে আপনার শিরোনাম এবং চিত্র সাজিয়ে তুলবে।

এছাড়াও প্রতিটি রিলেআউট এ আপডেট করুন নোট করুন


দ্রুতগতি

import UIKit

extension UIButton {
    // MARK: - UIButton+Aligment

    func alignContentVerticallyByCenter(offset:CGFloat = 10) {
        let buttonSize = frame.size

        if let titleLabel = titleLabel,
            let imageView = imageView {

            if let buttonTitle = titleLabel.text,
                let image = imageView.image {
                let titleString:NSString = NSString(string: buttonTitle)
                let titleSize = titleString.sizeWithAttributes([
                    NSFontAttributeName : titleLabel.font
                    ])
                let buttonImageSize = image.size

                let topImageOffset = (buttonSize.height - (titleSize.height + buttonImageSize.height + offset)) / 2
                let leftImageOffset = (buttonSize.width - buttonImageSize.width) / 2
                imageEdgeInsets = UIEdgeInsetsMake(topImageOffset,
                                                   leftImageOffset,
                                                   0,0)

                let titleTopOffset = topImageOffset + offset + buttonImageSize.height
                let leftTitleOffset = (buttonSize.width - titleSize.width) / 2 - image.size.width

                titleEdgeInsets = UIEdgeInsetsMake(titleTopOffset,
                                                   leftTitleOffset,
                                                   0,0)
            }
        }
    }
}

29

আপনি এটি ব্যবহার করে অনেক ঝামেলা এড়াতে পারেন -

myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;   
myButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;

এটি আপনার সমস্ত বিষয়বস্তু স্বয়ংক্রিয়ভাবে বামে সারিবদ্ধ করবে (বা যেখানে আপনি এটি চান)

সুইফট 3:

myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left;   
myButton.contentVerticalAlignment = UIControlContentVerticalAlignment.center;

myButton.contentVericalAlignment = UIControlContentVericalAlignment.center; // টাইপো সংশোধন করা হয়েছে
নৈশত

25

ইন Xcode 8.0 আপনি কেবল পরিবর্তন করে এটা করতে পারেনinsets আকার পরিদর্শক হবে।

ইউআইবাটন নির্বাচন করুন -> বৈশিষ্ট্য পরিদর্শক -> আকার পরিদর্শক যান এবং বিষয়বস্তু, চিত্র এবং শিরোনাম ইনসেটগুলি সংশোধন করুন।

এখানে চিত্র বর্ণনা লিখুন

এবং আপনি যদি ডান পাশের চিত্রটি পরিবর্তন করতে চান তবে আপনি কেবল অর্থশাস্ত্র Force Right-to-leftপরিদর্শককে অর্থশাস্ত্রিক সম্পত্তিটি পরিবর্তন করতে পারেন ।

এখানে চিত্র বর্ণনা লিখুন


আমার ক্ষেত্রে বোতামের চিত্রটি কখনই xcode 10 দিয়ে পাঠ্যের ডানদিকে যায় না? তুমি কি সাহায্য করতে পারো?
সতীশ মাভানী

হাই সতীশ, এটি এক্সকোড ১০-এর সাথেও দুর্দান্ত কাজ করছে আশা করি আপনি চিত্রটি ব্যাকগ্রাউন্ড ইমেজ নয়, সেটিও আকারের পরিদর্শক ব্যবহার করে চিত্রের পোকামাকড় পরিবর্তন করতে পারবেন change
সাহিল

18

আমি এই পার্টিতেও কিছুটা দেরি করেছি, তবে আমি মনে করি যে যুক্ত করতে আমার কিছু দরকারী রয়েছে: ও)।

আমি একটি UIButtonসাবক্লাস তৈরি করেছি যার উদ্দেশ্য বাটনটির চিত্রটি উল্লম্ব বা অনুভূমিকভাবে যেখানে লেআউটে রয়েছে তা চয়ন করতে সক্ষম হওয়া।

এর অর্থ হল যে আপনি এই ধরণের বোতাম তৈরি করতে পারেন: বোতাম বিভিন্ন ধরণের

এখানে আমার ক্লাসের সাহায্যে এই বোতামগুলি কীভাবে তৈরি করা যায় সে সম্পর্কে বিশদ:

func makeButton (imageVerticalAlignment:LayoutableButton.VerticalAlignment, imageHorizontalAlignment:LayoutableButton.HorizontalAlignment, title:String) -> LayoutableButton {
    let button = LayoutableButton ()

    button.imageVerticalAlignment = imageVerticalAlignment
    button.imageHorizontalAlignment = imageHorizontalAlignment

    button.setTitle(title, for: .normal)

    // add image, border, ...

    return button
}

let button1 = makeButton(imageVerticalAlignment: .center, imageHorizontalAlignment: .left, title: "button1")
let button2 = makeButton(imageVerticalAlignment: .center, imageHorizontalAlignment: .right, title: "button2")
let button3 = makeButton(imageVerticalAlignment: .top, imageHorizontalAlignment: .center, title: "button3")
let button4 = makeButton(imageVerticalAlignment: .bottom, imageHorizontalAlignment: .center, title: "button4")
let button5 = makeButton(imageVerticalAlignment: .bottom, imageHorizontalAlignment: .center, title: "button5")
button5.contentEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)

এটি করতে, আমি 2 টি বৈশিষ্ট্য যুক্ত করেছি: imageVerticalAlignmentএবং imageHorizontalAlignment। অবশ্যই, যদি আপনার বোতামটিতে কেবল একটি চিত্র বা শিরোনাম থাকে ... এই শ্রেণিটি মোটেও ব্যবহার করবেন না!

আমি নামের একটি বৈশিষ্ট্যও যুক্ত করেছি imageToTitleSpacing যা আপনাকে শিরোনাম এবং চিত্রের মধ্যে স্থান সামঞ্জস্য করতে দেয়।

এই শ্রেণীর তার সর্বোত্তম চেষ্টা সামঞ্জস্যপূর্ণ হতে আপনাকে ব্যবহার করতে চান imageEdgeInsets, titleEdgeInsetsএবং contentEdgeInsetsনতুন লেআউট বৈশিষ্ট্যাবলী সঙ্গে সরাসরি বা combinaison হবে।

@ শ্র্রন আমাদের ব্যাখ্যা হিসাবে, আমি বোতামের সামগ্রীর প্রান্তটি সঠিক করার জন্য যথাসাধ্য চেষ্টা করেছি (যেমন আপনি লাল সীমানা দিয়ে দেখতে পারেন)।

আপনি এটি ইন্টারফেস বিল্ডারেও ব্যবহার করতে পারেন:

  1. একটি ইউআইবাটন তৈরি করুন
  2. বোতাম ক্লাস পরিবর্তন করুন
  3. "কেন্দ্র", "শীর্ষ", "নীচে", "বাম" বা "ডান" ব্যবহার করে বিন্যাসযোগ্য বৈশিষ্ট্যগুলি সামঞ্জস্য করুন বোতাম বৈশিষ্ট্য

এখানে কোড ( সংক্ষেপে ):

@IBDesignable
class LayoutableButton: UIButton {

    enum VerticalAlignment : String {
        case center, top, bottom, unset
    }


    enum HorizontalAlignment : String {
        case center, left, right, unset
    }


    @IBInspectable
    var imageToTitleSpacing: CGFloat = 8.0 {
        didSet {
            setNeedsLayout()
        }
    }


    var imageVerticalAlignment: VerticalAlignment = .unset {
        didSet {
            setNeedsLayout()
        }
    }

    var imageHorizontalAlignment: HorizontalAlignment = .unset {
        didSet {
            setNeedsLayout()
        }
    }

    @available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'imageVerticalAlignment' instead.")
    @IBInspectable
    var imageVerticalAlignmentName: String {
        get {
            return imageVerticalAlignment.rawValue
        }
        set {
            if let value = VerticalAlignment(rawValue: newValue) {
                imageVerticalAlignment = value
            } else {
                imageVerticalAlignment = .unset
            }
        }
    }

    @available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'imageHorizontalAlignment' instead.")
    @IBInspectable
    var imageHorizontalAlignmentName: String {
        get {
            return imageHorizontalAlignment.rawValue
        }
        set {
            if let value = HorizontalAlignment(rawValue: newValue) {
                imageHorizontalAlignment = value
            } else {
                imageHorizontalAlignment = .unset
            }
        }
    }

    var extraContentEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero

    override var contentEdgeInsets: UIEdgeInsets {
        get {
            return super.contentEdgeInsets
        }
        set {
            super.contentEdgeInsets = newValue
            self.extraContentEdgeInsets = newValue
        }
    }

    var extraImageEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero

    override var imageEdgeInsets: UIEdgeInsets {
        get {
            return super.imageEdgeInsets
        }
        set {
            super.imageEdgeInsets = newValue
            self.extraImageEdgeInsets = newValue
        }
    }

    var extraTitleEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero

    override var titleEdgeInsets: UIEdgeInsets {
        get {
            return super.titleEdgeInsets
        }
        set {
            super.titleEdgeInsets = newValue
            self.extraTitleEdgeInsets = newValue
        }
    }

    //Needed to avoid IB crash during autolayout
    override init(frame: CGRect) {
        super.init(frame: frame)
    }


    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        self.imageEdgeInsets = super.imageEdgeInsets
        self.titleEdgeInsets = super.titleEdgeInsets
        self.contentEdgeInsets = super.contentEdgeInsets
    }

    override func layoutSubviews() {
        if let imageSize = self.imageView?.image?.size,
            let font = self.titleLabel?.font,
            let textSize = self.titleLabel?.attributedText?.size() ?? self.titleLabel?.text?.size(attributes: [NSFontAttributeName: font]) {

            var _imageEdgeInsets = UIEdgeInsets.zero
            var _titleEdgeInsets = UIEdgeInsets.zero
            var _contentEdgeInsets = UIEdgeInsets.zero

            let halfImageToTitleSpacing = imageToTitleSpacing / 2.0

            switch imageVerticalAlignment {
            case .bottom:
                _imageEdgeInsets.top = (textSize.height + imageToTitleSpacing) / 2.0
                _imageEdgeInsets.bottom = (-textSize.height - imageToTitleSpacing) / 2.0
                _titleEdgeInsets.top = (-imageSize.height - imageToTitleSpacing) / 2.0
                _titleEdgeInsets.bottom = (imageSize.height + imageToTitleSpacing) / 2.0
                _contentEdgeInsets.top = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
                _contentEdgeInsets.bottom = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
                //only works with contentVerticalAlignment = .center
                contentVerticalAlignment = .center
            case .top:
                _imageEdgeInsets.top = (-textSize.height - imageToTitleSpacing) / 2.0
                _imageEdgeInsets.bottom = (textSize.height + imageToTitleSpacing) / 2.0
                _titleEdgeInsets.top = (imageSize.height + imageToTitleSpacing) / 2.0
                _titleEdgeInsets.bottom = (-imageSize.height - imageToTitleSpacing) / 2.0
                _contentEdgeInsets.top = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
                _contentEdgeInsets.bottom = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
                //only works with contentVerticalAlignment = .center
                contentVerticalAlignment = .center
            case .center:
                //only works with contentVerticalAlignment = .center
                contentVerticalAlignment = .center
                break
            case .unset:
                break
            }

            switch imageHorizontalAlignment {
            case .left:
                _imageEdgeInsets.left = -halfImageToTitleSpacing
                _imageEdgeInsets.right = halfImageToTitleSpacing
                _titleEdgeInsets.left = halfImageToTitleSpacing
                _titleEdgeInsets.right = -halfImageToTitleSpacing
                _contentEdgeInsets.left = halfImageToTitleSpacing
                _contentEdgeInsets.right = halfImageToTitleSpacing
            case .right:
                _imageEdgeInsets.left = textSize.width + halfImageToTitleSpacing
                _imageEdgeInsets.right = -textSize.width - halfImageToTitleSpacing
                _titleEdgeInsets.left = -imageSize.width - halfImageToTitleSpacing
                _titleEdgeInsets.right = imageSize.width + halfImageToTitleSpacing
                _contentEdgeInsets.left = halfImageToTitleSpacing
                _contentEdgeInsets.right = halfImageToTitleSpacing
            case .center:
                _imageEdgeInsets.left = textSize.width / 2.0
                _imageEdgeInsets.right = -textSize.width / 2.0
                _titleEdgeInsets.left = -imageSize.width / 2.0
                _titleEdgeInsets.right = imageSize.width / 2.0
                _contentEdgeInsets.left = -((imageSize.width + textSize.width) - max (imageSize.width, textSize.width)) / 2.0
                _contentEdgeInsets.right = -((imageSize.width + textSize.width) - max (imageSize.width, textSize.width)) / 2.0
            case .unset:
                break
            }

            _contentEdgeInsets.top += extraContentEdgeInsets.top
            _contentEdgeInsets.bottom += extraContentEdgeInsets.bottom
            _contentEdgeInsets.left += extraContentEdgeInsets.left
            _contentEdgeInsets.right += extraContentEdgeInsets.right

            _imageEdgeInsets.top += extraImageEdgeInsets.top
            _imageEdgeInsets.bottom += extraImageEdgeInsets.bottom
            _imageEdgeInsets.left += extraImageEdgeInsets.left
            _imageEdgeInsets.right += extraImageEdgeInsets.right

            _titleEdgeInsets.top += extraTitleEdgeInsets.top
            _titleEdgeInsets.bottom += extraTitleEdgeInsets.bottom
            _titleEdgeInsets.left += extraTitleEdgeInsets.left
            _titleEdgeInsets.right += extraTitleEdgeInsets.right

            super.imageEdgeInsets = _imageEdgeInsets
            super.titleEdgeInsets = _titleEdgeInsets
            super.contentEdgeInsets = _contentEdgeInsets

        } else {
            super.imageEdgeInsets = extraImageEdgeInsets
            super.titleEdgeInsets = extraTitleEdgeInsets
            super.contentEdgeInsets = extraContentEdgeInsets
        }

        super.layoutSubviews()
    }
}

1
আমি কিছু জিনিস ঠিক করেছি error: IB Designables: Failed to update auto layout status: The agent crashed, gist.github.com/nebiros/ecf69ff9cb90568edde071386c6c4ddb
nebiros

দয়া করে @nebiros আপনি কী ব্যাখ্যা করতে পারেন এবং কীভাবে আপনি এটি ঠিক করেছেন, দয়া করে?
gbitaudeau

@gbitaudeau আমি যখন স্ক্রিপ্টটি অনুলিপি করে আটকিয়ে দেব তখন আমি সেই ত্রুটিটি পেয়েছি error: IB Designables: Failed to update auto layout status: The agent crashedকারণ , init(frame: CGRect)ওভাররাইড করা হয়নি, এছাড়াও আমি @availableটীকা যুক্ত করছি ..., আপনি diff -Naurচাইলে করতে পারেন, ;-)
নেবিরোস

9

অ্যাকাউন্টের স্থানীয় পরিবর্তনের জন্য রিলে অ্যাভ্রনের উত্তরে একটি ছোট সংযোজন:

extension UIButton {
    func centerTextAndImage(spacing: CGFloat) {
        let insetAmount = spacing / 2
        let writingDirection = UIApplication.sharedApplication().userInterfaceLayoutDirection
        let factor: CGFloat = writingDirection == .LeftToRight ? 1 : -1

        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount*factor, bottom: 0, right: insetAmount*factor)
        self.titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount*factor, bottom: 0, right: -insetAmount*factor)
        self.contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
    }
}

6

সুইফট 4.x

extension UIButton {
    func centerTextAndImage(spacing: CGFloat) {
        let insetAmount = spacing / 2
        let writingDirection = UIApplication.shared.userInterfaceLayoutDirection
        let factor: CGFloat = writingDirection == .leftToRight ? 1 : -1

        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount*factor, bottom: 0, right: insetAmount*factor)
        self.titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount*factor, bottom: 0, right: -insetAmount*factor)
        self.contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
    }
}

ব্যবহার :

button.centerTextAndImage(spacing: 10.0)

কাস্টম ইমেজ আকারের সাথে কীভাবে ব্যবহার করতে পারেন?
মিডহান পি

2

আমি কোড bewlow লিখুন। এটি পণ্য সংস্করণে ভাল কাজ করে। সাপ্রোট সুইফট 4.2 +

extension UIButton{
 enum ImageTitleRelativeLocation {
    case imageUpTitleDown
    case imageDownTitleUp
    case imageLeftTitleRight
    case imageRightTitleLeft
}
 func centerContentRelativeLocation(_ relativeLocation: 
                                      ImageTitleRelativeLocation,
                                   spacing: CGFloat = 0) {
    assert(contentVerticalAlignment == .center,
           "only works with contentVerticalAlignment = .center !!!")

    guard (title(for: .normal) != nil) || (attributedTitle(for: .normal) != nil) else {
        assert(false, "TITLE IS NIL! SET TITTLE FIRST!")
        return
    }

    guard let imageSize = self.currentImage?.size else {
        assert(false, "IMGAGE IS NIL! SET IMAGE FIRST!!!")
        return
    }
    guard let titleSize = titleLabel?
        .systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) else {
            assert(false, "TITLELABEL IS NIL!")
            return
    }

    let horizontalResistent: CGFloat
    // extend contenArea in case of title is shrink
    if frame.width < titleSize.width + imageSize.width {
        horizontalResistent = titleSize.width + imageSize.width - frame.width
        print("horizontalResistent", horizontalResistent)
    } else {
        horizontalResistent = 0
    }

    var adjustImageEdgeInsets: UIEdgeInsets = .zero
    var adjustTitleEdgeInsets: UIEdgeInsets = .zero
    var adjustContentEdgeInsets: UIEdgeInsets = .zero

    let verticalImageAbsOffset = abs((titleSize.height + spacing) / 2)
    let verticalTitleAbsOffset = abs((imageSize.height + spacing) / 2)

    switch relativeLocation {
    case .imageUpTitleDown:

        adjustImageEdgeInsets.top = -verticalImageAbsOffset
        adjustImageEdgeInsets.bottom = verticalImageAbsOffset
        adjustImageEdgeInsets.left = titleSize.width / 2 + horizontalResistent / 2
        adjustImageEdgeInsets.right = -titleSize.width / 2 - horizontalResistent / 2

        adjustTitleEdgeInsets.top = verticalTitleAbsOffset
        adjustTitleEdgeInsets.bottom = -verticalTitleAbsOffset
        adjustTitleEdgeInsets.left = -imageSize.width / 2 + horizontalResistent / 2
        adjustTitleEdgeInsets.right = imageSize.width / 2 - horizontalResistent / 2

        adjustContentEdgeInsets.top = spacing
        adjustContentEdgeInsets.bottom = spacing
        adjustContentEdgeInsets.left = -horizontalResistent
        adjustContentEdgeInsets.right = -horizontalResistent
    case .imageDownTitleUp:
        adjustImageEdgeInsets.top = verticalImageAbsOffset
        adjustImageEdgeInsets.bottom = -verticalImageAbsOffset
        adjustImageEdgeInsets.left = titleSize.width / 2 + horizontalResistent / 2
        adjustImageEdgeInsets.right = -titleSize.width / 2 - horizontalResistent / 2

        adjustTitleEdgeInsets.top = -verticalTitleAbsOffset
        adjustTitleEdgeInsets.bottom = verticalTitleAbsOffset
        adjustTitleEdgeInsets.left = -imageSize.width / 2 + horizontalResistent / 2
        adjustTitleEdgeInsets.right = imageSize.width / 2 - horizontalResistent / 2

        adjustContentEdgeInsets.top = spacing
        adjustContentEdgeInsets.bottom = spacing
        adjustContentEdgeInsets.left = -horizontalResistent
        adjustContentEdgeInsets.right = -horizontalResistent
    case .imageLeftTitleRight:
        adjustImageEdgeInsets.left = -spacing / 2
        adjustImageEdgeInsets.right = spacing / 2

        adjustTitleEdgeInsets.left = spacing / 2
        adjustTitleEdgeInsets.right = -spacing / 2

        adjustContentEdgeInsets.left = spacing
        adjustContentEdgeInsets.right = spacing
    case .imageRightTitleLeft:
        adjustImageEdgeInsets.left = titleSize.width + spacing / 2
        adjustImageEdgeInsets.right = -titleSize.width - spacing / 2

        adjustTitleEdgeInsets.left = -imageSize.width - spacing / 2
        adjustTitleEdgeInsets.right = imageSize.width + spacing / 2

        adjustContentEdgeInsets.left = spacing
        adjustContentEdgeInsets.right = spacing
    }

    imageEdgeInsets = adjustImageEdgeInsets
    titleEdgeInsets = adjustTitleEdgeInsets
    contentEdgeInsets = adjustContentEdgeInsets

    setNeedsLayout()
}
}

1

ইমেজএডজিনসেটস কীভাবে ব্যবহার করতে হয় তার একটি সাধারণ উদাহরণ এখানে একটি হিটটেবল অঞ্চল 10 পিক্সেল চারপাশে বড় (30x50) একটি 30x30 বোতাম তৈরি করবে

    var expandHittableAreaAmt : CGFloat = 10
    var buttonWidth : CGFloat = 30
    var button = UIButton.buttonWithType(UIButtonType.Custom) as UIButton
    button.frame = CGRectMake(0, 0, buttonWidth+expandHittableAreaAmt, buttonWidth+expandHittableAreaAmt)
    button.imageEdgeInsets = UIEdgeInsetsMake(expandHittableAreaAmt, expandHittableAreaAmt, expandHittableAreaAmt, expandHittableAreaAmt)
    button.setImage(UIImage(named: "buttonImage"), forState: .Normal)
    button.addTarget(self, action: "didTouchButton:", forControlEvents:.TouchUpInside)

0

সুইফট 3 এ একটি মার্জিত উপায় এবং এটি বোঝার জন্য আরও ভাল:

override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
    let leftMargin:CGFloat = 40
    let imgWidth:CGFloat = 24
    let imgHeight:CGFloat = 24
    return CGRect(x: leftMargin, y: (contentRect.size.height-imgHeight) * 0.5, width: imgWidth, height: imgHeight)
}

override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
    let leftMargin:CGFloat = 80
    let rightMargin:CGFloat = 80
    return CGRect(x: leftMargin, y: 0, width: contentRect.size.width-leftMargin-rightMargin, height: contentRect.size.height)
}
override func backgroundRect(forBounds bounds: CGRect) -> CGRect {
    let leftMargin:CGFloat = 10
    let rightMargin:CGFloat = 10
    let topMargin:CGFloat = 10
    let bottomMargin:CGFloat = 10
    return CGRect(x: leftMargin, y: topMargin, width: bounds.size.width-leftMargin-rightMargin, height: bounds.size.height-topMargin-bottomMargin)
}
override func contentRect(forBounds bounds: CGRect) -> CGRect {
    let leftMargin:CGFloat = 5
    let rightMargin:CGFloat = 5
    let topMargin:CGFloat = 5
    let bottomMargin:CGFloat = 5
    return CGRect(x: leftMargin, y: topMargin, width: bounds.size.width-leftMargin-rightMargin, height: bounds.size.height-topMargin-bottomMargin)
}

-1

দ্রবণটির দ্রুতগতি 4.2 সংস্করণটি নিম্নলিখিত হবে:

let spacing: CGFloat = 10 // the amount of spacing to appear between image and title
self.button?.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: spacing)
self.button?.titleEdgeInsets = UIEdgeInsets(top: 0, left: spacing, bottom: 0, right: 0)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.