Як встановити вирівнювання у верхньому лівому куті для UILabel для програми iOS?


99

Я додав одну мітку у свій файл ніб, тоді її потрібно мати ліве верхнє ліве позначення для цієї мітки. Оскільки я надаю текст під час виконання, тому не впевнений, що кількість рядків є. Отже, якщо текст містить лише один рядок, тоді він виглядає як вирівняний по вертикалі по центру. Це вирівнювання не відповідає моїй відповідній етикетці перед ним.

Наприклад:

введіть тут опис зображення

Що дивно :(

Чи є спосіб встановити текст мітки відповідно до вирівнювання вгорі-вліво?


Відповіді:



64

Це зробити досить просто. Створіть UILabelпідкадру із verticalAlignmentвластивістю та перевіртеtextRectForBounds:limitedToNumberOfLines щоб повернути правильні межі для верхнього, середнього чи нижнього вертикального вирівнювання. Ось код:

SOLabel.h

#import <UIKit/UIKit.h>

typedef enum
{
    VerticalAlignmentTop = 0, // default
    VerticalAlignmentMiddle,
    VerticalAlignmentBottom,
} VerticalAlignment;

@interface SOLabel : UILabel

   @property (nonatomic, readwrite) VerticalAlignment verticalAlignment;

@end

SOLabel.m

@implementation SOLabel

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (!self) return nil;

    // set inital value via IVAR so the setter isn't called
    _verticalAlignment = VerticalAlignmentTop;

    return self;
}

-(VerticalAlignment) verticalAlignment
{
    return _verticalAlignment;
}

-(void) setVerticalAlignment:(VerticalAlignment)value
{
    _verticalAlignment = value;
    [self setNeedsDisplay];
}

// align text block according to vertical alignment settings
-(CGRect)textRectForBounds:(CGRect)bounds 
    limitedToNumberOfLines:(NSInteger)numberOfLines
{
   CGRect rect = [super textRectForBounds:bounds 
                   limitedToNumberOfLines:numberOfLines];
    CGRect result;
    switch (_verticalAlignment)
    {
       case VerticalAlignmentTop:
          result = CGRectMake(bounds.origin.x, bounds.origin.y, 
                              rect.size.width, rect.size.height);
           break;

       case VerticalAlignmentMiddle:
          result = CGRectMake(bounds.origin.x, 
                    bounds.origin.y + (bounds.size.height - rect.size.height) / 2,
                    rect.size.width, rect.size.height);
          break;

       case VerticalAlignmentBottom:
          result = CGRectMake(bounds.origin.x, 
                    bounds.origin.y + (bounds.size.height - rect.size.height),
                    rect.size.width, rect.size.height);
          break;

       default:
          result = bounds;
          break;
    }
    return result;
}

-(void)drawTextInRect:(CGRect)rect
{
    CGRect r = [self textRectForBounds:rect 
                limitedToNumberOfLines:self.numberOfLines];
    [super drawTextInRect:r];
}

@end

3
Я також спробував багато інших рішень тут на SO перед тим, як натрапити на це. Це спрацювало чудово! Майте на увазі, що якщо ви робите це в StoryBoard, переконайтеся, що ви встановили атрибут CustomClass для SOLabel (або як ви вирішите його назвати) замість UILabel (у інспекторі утиліт).
TMc

Це дуже корисно, дякую. Він не працює для центру або праворуч вирівняного тексту, але використання bounds.size.widthзамість rect.size.widthin, textRectForBounds:limitedToNumberOfLines:здається, виправить це.
Джефф Хекворт,

1
Якщо ви зустріли «Потік 1: EXC_BAD_ACCESS (Код 2, адреса = 0x ...)» в iOS 9 Xcode 7, просто видаліть сеттер та геттер - (VerticalAlignment) verticalAlignment; та - (void) setVerticalAlignment: значення функції (VerticalAlignment), оскільки змінна є @property. Він синтезований і містить аксесуари.
felixwcf

у мене є деякі зміни тут у методі: "textRectForBounds" - результат = CGRectMake (rect.origin.x, bounds.origin.y, rect.size.width, rect.size.height); Щоб зробити мої роботи для rightAlignment UILable.
g212gs

50

Я знайшов рішення за допомогою функції AutoLayout в StoryBoard.

1) Встановіть кількість рядків на 0, а вирівнювання тексту - наліво.

введіть тут опис зображення

2) Встановити обмеження по висоті.

введіть тут опис зображення

3) Обмеження висоти має бути у співвідношенні - менше або рівне

введіть тут опис зображення

4)

   override func viewWillLayoutSubviews() {
        sampleLabel.sizeToFit()
    }

Я отримав такий результат:

введіть тут опис зображення


2
Працює як шарм, навіть у UITableViewCell із повторним використанням.
alex.bour

Ви viewWillLayoutSubviewsпоміщаєте файл у контролер або файл комірки? Якщо контролер, як він отримує доступ до UILabel з комірки?
Craig.Pearce

Де ви ставите крок 4? Як новий користувач, я був радий отримати суто рішення інтерфейсу, тоді цей код з’являється з нізвідки, і нам не кажуть, куди його поставити
velkoon

Або на SampleClass.swift або SampleTableViewCell.swift
AG

Це має бути Рішення. Працює ідеально, не потрібен злом або підкласифікація.
Цікаво101,

44

SOLabel працює для мене.

Свіфт 3 і 5:

Ця версія була оновлена ​​з оригіналу, щоб забезпечити підтримку мов RTL:

public class VerticalAlignLabel: UILabel {
    enum VerticalAlignment {
        case top
        case middle
        case bottom
    }

    var verticalAlignment : VerticalAlignment = .top {
        didSet {
            setNeedsDisplay()
        }
    }

    override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
        let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)

        if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft {
            switch verticalAlignment {
            case .top:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
            case .middle:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
            case .bottom:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
            }
        } else {
            switch verticalAlignment {
            case .top:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
            case .middle:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
            case .bottom:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
            }
        }
    }

    override public func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}

Свіфт 1:

class UIVerticalAlignLabel: UILabel {

enum VerticalAlignment : Int {
    case VerticalAlignmentTop = 0
    case VerticalAlignmentMiddle = 1
    case VerticalAlignmentBottom = 2
}

var verticalAlignment : VerticalAlignment = .VerticalAlignmentTop {
    didSet {
        setNeedsDisplay()
    }
}

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

override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
    let rect = super.textRectForBounds(bounds, limitedToNumberOfLines: limitedToNumberOfLines)

    switch(verticalAlignment) {
        case .VerticalAlignmentTop:
            return CGRectMake(bounds.origin.x, bounds.origin.y, rect.size.width, rect.size.height)
        case .VerticalAlignmentMiddle:
            return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height) / 2, rect.size.width, rect.size.height)
        case .VerticalAlignmentBottom:
            return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height), rect.size.width, rect.size.height)
        default:
            return bounds
    }
}

override func drawTextInRect(rect: CGRect) {
    let r = self.textRectForBounds(rect, limitedToNumberOfLines: self.numberOfLines)
    super.drawTextInRect(r)
    }
}

Якщо я спробую створити мітку за допомогою цього коду: var myLabel = VerticalAlignLabel (), я отримую "Відсутній аргумент для параметра 'кодер' у виклику". Як я можу створити мітку за допомогою цього підкласу VerticalAlignLabel?
RanLearns

1
Спробуйте версію Swift 3 зараз - у мене був необхідний init, який не потрібен.
totiG

14

У моєму випадку це була bottom spaceпроблема обмежень. Я встановив це = 16.

Коли я встановив це значення bottom to >= 16, це питання було вирішено.

Крім того, якщо у вас є обмеження висоти на етикетці, вам потрібно його видалити.

Ось вигляд обмеження моєї мітки в інспекторі розмірів:

обмеження


У мене немає варіантів обмежень, коли я вибираю мітку.
велькон

Найпростіше виправлення - нехай обмеження та автоматичний макет подбають про це. Дякую!
Джейсон

13

У своєму коді

label.text = @"some text";
[label sizeToFit];

Пам'ятайте, що якщо ви використовуєте це в комірках таблиці або інших представленнях, які переробляються з різними даними, вам потрібно буде десь зберегти вихідний кадр і скинути його перед викликом sizeToFit.


На цьому етапі я рекомендую фактично залишити це все для авторозкладки. Це вже не потрібно.
n13,

9

Я знайшов інше рішення цієї ж проблеми. Я використовував UITextViewзамість UILabelі перемикав editable()функцію на false.


@geekyaleks Чому це німий хак? Здається, це пристойний обхідний шлях, чи є з ним інші проблеми, крім того, що це не пряма відповідь на питання?
Крістофер Ларсен

Це не доречно, оскільки ви не використовуєте відповідний компонент інтерфейсу для роботи. Це НЕ повинно бути компромісом для чогось такого простого, як вертикальне вирівнювання. Потрібно використовувати відповідний компонент для роботи. Все інше - це злом ...
geekyaleks

7

У мене також була ця проблема, але я виявив порядок, в якому ви встановлюєте властивості та методи UILabel!

Якщо ви зателефонували [label sizeToFit]раніше, label.font = [UIFont fontWithName:@"Helvetica" size:14];текст не вирівнюється до верху, але якщо ви поміняєте їх місцями, це робить!

Я також помітив, що налаштування тексту спочатку також має значення.

Сподіваюся, це допомагає.


Чудово. sizeToFit () слід викликати в останню чергу.
MKatleast3

4

Оскільки ви використовуєте конструктор інтерфейсів, встановіть обмеження для вашої мітки (обов’язково встановіть також висоту та ширину). Потім в Інспекторі розмірів перевірте висоту етикетки. Там ви захочете, щоб він читав> = замість =. Потім у реалізації для цього контролера перегляду встановіть кількість рядків на 0 (також можна зробити в IB) і встановіть мітку [label sizeToFit]; і оскільки текст набирає довжину, мітка зростатиме у висоту і зберігатиме текст у верхньому лівому куті.


4

Якщо вам потрібен не редагований текст, який за замовчуванням починається у верхньому лівому куті, ви можете просто використовувати перегляд тексту замість мітки, а потім встановити його стан не редагованим, наприклад:

textview.isEditable = false

Набагато простіше, ніж возитися з ярликами ...

Ура!


3

Рішення з SoLabel працює, дякую.

Нижче я додав версію monotouch:

    public class UICustomLabel : UILabel
{
    private UITextVerticalAlignment _textVerticalAlignment;

    public UICustomLabel()
    {
        TextVerticalAlignment = UITextVerticalAlignment.Top;
    }

    public UITextVerticalAlignment TextVerticalAlignment
    {
        get
        {
            return _textVerticalAlignment;
        }
        set
        {
            _textVerticalAlignment = value;
            SetNeedsDisplay();
        }
    }

    public override void DrawText(RectangleF rect)
    {
        var bound = TextRectForBounds(rect, Lines);
        base.DrawText(bound);
    }

    public override RectangleF TextRectForBounds(RectangleF bounds, int numberOfLines)
    {
        var rect = base.TextRectForBounds(bounds, numberOfLines);
        RectangleF resultRect;
        switch (TextVerticalAlignment)
        {
            case UITextVerticalAlignment.Top:
                resultRect = new RectangleF(bounds.X, bounds.Y, rect.Size.Width, rect.Size.Height);
                break;
            case UITextVerticalAlignment.Middle:
                resultRect = new RectangleF(bounds.X,
                                            bounds.Y + (bounds.Size.Height - rect.Size.Height)/2,
                                            rect.Size.Width, rect.Size.Height);
                break;
            case UITextVerticalAlignment.Bottom:
                resultRect = new RectangleF(bounds.X,
                                            bounds.Y + (bounds.Size.Height - rect.Size.Height),
                                            rect.Size.Width, rect.Size.Height);
                break;

            default:
                resultRect = bounds;
                break;
        }

        return resultRect;
    }
}

public enum UITextVerticalAlignment
{
    Top = 0, // default
    Middle,
    Bottom
}

3

Найпростіший і найпростіший спосіб - це вставити Label у StackView та встановити вісь StackView на горизонтальну, вирівняти по верхній частині в інспекторі атрибутів з Storyboard, як показано тут .


2

Спираючись на дивовижну відповідь totiG, я створив клас IBDesignable, який дозволяє надзвичайно легко налаштувати вертикальне вирівнювання UILabel прямо з StoryBoard. Просто переконайтеся, що ви встановили для класу UILabel значення 'VerticalAlignLabel' від інспектора ідентифікації StoryBoard. Якщо вертикальне вирівнювання не набуває чинності, перейдіть до редактора-> Оновити всі перегляди, що повинно зробити трюк.

Як це працює: Як тільки ви правильно встановите клас свого UILabel, розкадровка повинна показати вам поле введення, яке приймає ціле число (код вирівнювання).

Оновлення: я додав підтримку центрованих міток ~ Sev


Введіть 0 для вирівнювання вгорі

Введіть 1 для середньої вирівнювання

Введіть 2 для вирівнювання внизу

    @IBDesignable class VerticalAlignLabel: UILabel {
    
    @IBInspectable var alignmentCode: Int = 0 {
        didSet {
            applyAlignmentCode()
        }
    }
    
    func applyAlignmentCode() {
        switch alignmentCode {
        case 0:
            verticalAlignment = .top
        case 1:
            verticalAlignment = .topcenter
        case 2:
            verticalAlignment = .middle
        case 3:
            verticalAlignment = .bottom
        default:
            break
        }
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        self.applyAlignmentCode()
    }
    
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        
        self.applyAlignmentCode()
    }
    
    enum VerticalAlignment {
        case top
        case topcenter
        case middle
        case bottom
    }
    
    var verticalAlignment : VerticalAlignment = .top {
        didSet {
            setNeedsDisplay()
        }
    }
    
    override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
        let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)
        
        if #available(iOS 9.0, *) {
            if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft {
                switch verticalAlignment {
                case .top:
                    return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .topcenter:
                    return CGRect(x: self.bounds.size.width - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .middle:
                    return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
                case .bottom:
                    return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
                }
            } else {
                switch verticalAlignment {
                case .top:
                    return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .topcenter:
                    return CGRect(x: (self.bounds.size.width / 2 ) - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .middle:
                    return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
                case .bottom:
                    return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
                }
            }
        } else {
            // Fallback on earlier versions
            return rect
        }
    }
    
    override public func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}


2

ви також можете просто змінити свій UILabel на UITextView, оскільки вони в основному роблять те саме, крім переваги UITextView, що текст автоматично вирівнюється вліво зліва


1

У мене є ця проблема, але мітка була в UITableViewCell, і в фонді, що найпростішим способом вирішити проблему було створити порожній UIView і встановити мітку всередині нього з обмеженнями лише зверху та ліворуч, при виключенні прокляття встановіть кількість рядків 0


0

Для iOS 7 це те, що я зробив і працював для мене

@implementation UILabel (VerticalAlign)
- (void)alignTop
{
    CGSize boundingRectSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX);
    NSDictionary *attributes = @{NSFontAttributeName : self.font};
    CGRect labelSize = [self.text boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                              attributes:attributes
                                                 context:nil];
    int numberOfLines= ceil(labelSize.size.height / self.font.lineHeight);

    CGRect newFrame = self.frame;
    newFrame.size.height = numberOfLines * self.font.lineHeight;
    self.frame = newFrame;
}

- (void)alignBottom
{
    CGSize boundingRectSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX);
    NSDictionary *attributes = @{NSFontAttributeName : self.font};
    CGRect labelSize = [self.text boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                            attributes:attributes
                                               context:nil];
    int numberOfLines= ceil(labelSize.size.height / self.font.lineHeight);

    int numberOfNewLined = (self.frame.size.height/self.font.lineHeight) - numberOfLines;

    NSMutableString *newLines = [NSMutableString string];
    for(int i=0; i< numberOfNewLined; i++){
        [newLines appendString:@"\n"];
    }
    [newLines appendString:self.text];
    self.text = [newLines mutableCopy];
}

0

Swift 2.0 :: Використання розширення UILabel

Зробіть постійні значення перерахування в порожньому файлі Swift.

//  AppRef.swift

import UIKit
import Foundation

enum UILabelTextPositions : String {

 case VERTICAL_ALIGNMENT_TOP = "VerticalAlignmentTop"
 case VERTICAL_ALIGNMENT_MIDDLE = "VerticalAlignmentMiddle"
 case VERTICAL_ALIGNMENT_BOTTOM = "VerticalAlignmentBottom"

}

Використання розширення UILabel:

Створіть порожній клас Swift і назвіть його. Додайте наступне.

//  AppExtensions.swift

import Foundation
import UIKit

    extension UILabel{ 
     func makeLabelTextPosition (sampleLabel :UILabel?, positionIdentifier : String) -> UILabel
     {
      let rect = sampleLabel!.textRectForBounds(bounds, limitedToNumberOfLines: 0)

      switch positionIdentifier
      {
      case "VerticalAlignmentTop":
       sampleLabel!.frame = CGRectMake(bounds.origin.x+5, bounds.origin.y, rect.size.width, rect.size.height)
       break;

      case "VerticalAlignmentMiddle":
       sampleLabel!.frame = CGRectMake(bounds.origin.x+5,bounds.origin.y + (bounds.size.height - rect.size.height) / 2,
        rect.size.width, rect.size.height);
       break;

      case "VerticalAlignmentBottom":
       sampleLabel!.frame = CGRectMake(bounds.origin.x+5, bounds.origin.y + (bounds.size.height - rect.size.height),rect.size.width, rect.size.height);
       break;

      default:
       sampleLabel!.frame = bounds;
       break;
      }
      return sampleLabel!

     }
    }

Використання:

myMessageLabel.makeLabelTextPosition(messageLabel, positionIdentifier: UILabelTextPositions.VERTICAL_ALIGNMENT_TOP.rawValue)

Не могли б ви пояснити, для чого це потрібно sampleLabel: UILabel??
Craig.Pearce

У цій функції makeLabelTextPosition (sampleLabel: UILabel ?, positionIdentifier: String) {}, вам потрібно передати об’єкт UILabel.
AG

0

Swift 3 версія відповіді @ totiG

class UIVerticalAlignLabel: UILabel {
    enum VerticalAlignment : Int {
        case VerticalAlignmentTop = 0
        case VerticalAlignmentMiddle = 1
        case VerticalAlignmentBottom = 2
    }

    @IBInspectable var verticalAlignment : VerticalAlignment = .VerticalAlignmentTop {
        didSet {
            setNeedsDisplay()
        }
    }

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

    override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
        let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)

        switch(verticalAlignment) {
        case .VerticalAlignmentTop:
            return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
        case .VerticalAlignmentMiddle:
            return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
        case .VerticalAlignmentBottom:
            return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
        }
    }

    override func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}

0

Відповідь @ totiG правильна і вирішила мою проблему. Але я знайшов проблему під час впровадження цього методу на менших пристроях, таких як 5s, SE, це не працює для мене. Я повинен набір label.sizeToFit()вoverride func layoutSubViews()

override func layoutSubViews() {
    super.layoutSubViews()
    // Do other works if needed
    label.sizeToFit()
}

0

Швидкий 5

Це просто, порядок властивостей - це все.

titleLabel.frame = CGRect(x: 20, y: 20, width: 374, height: 291.2)
titleLabel.backgroundColor = UIColor.clear //set a light color to see the frame
titleLabel.textAlignment = .left
titleLabel.lineBreakMode = .byTruncatingTail
titleLabel.numberOfLines = 4
titleLabel.font = UIFont(name: "HelveticaNeue-Bold", size: 35)
titleLabel.text = "Example"
titleLabel.sizeToFit()
self.view.addSubview(titleLabel)

-2

Як встановити вирівнювання у верхньому лівому куті для UILabel для програми iOS? Для мене працює режим мітки "Вміст ліворуч", дякую вам дуже:
Як встановити вирівнювання у верхньому лівому куті для UILabel для програми iOS?  Етикетка Встановіть для режиму вмісту значення «Зліва зліва» для мене працює, велике спасибі


1
Не робить для мене абсолютно нічого. Це здається інтуїтивно зрозумілим, як це повинно бути рішенням, і саме тому я звернувся до Google, коли це не спрацювало (або, здавалося б, все з цим підключити).
велькон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.