UICollectionView всередині UITableViewCell - динамічна висота?


125

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

Наша всебічна робота UIViewControllerбула створена на Дошках розкадрів та використовує автоматичний макет. Але я не знаю, як динамічно збільшувати висоту на UITableViewCellоснові висоти UICollectionView.

Хто-небудь може дати кілька порад чи порад, як це досягти?


Ви можете розповісти трохи більше про макет, який ви намагаєтеся виконати? Чи UITableViewCellвідрізняється висота від його акустичного виду столу? Вам потрібна вертикальна прокрутка як на, так UICollectionViewі наUITableView
apouche

3
Висота UITableViewCell повинна бути динамічною, виходячи з висоти UICollectionView, що є частиною комірки подання таблиці. Макет мого UICollectionView - це 4 стовпчики та динамічна кількість рядків. Отже, зі 100 пунктами я мав би 4 стовпчики та 25 рядків у своєму UICollectionView. Висота конкретної комірки - як зазначено у висоті UITableViewForForWowAtIndexPath - повинна бути в змозі регулюватись залежно від розміру цього UICollectionView. Це трохи зрозуміліше?
Shadowman

@Shadowman, будь ласка, запропонуйте мені вирішити цю ситуацію
Раві Оджа

Відповіді:


127

Правильна відповідь ТАК , ви можете це зробити.

Я зіткнувся з цією проблемою кілька тижнів тому. Насправді простіше, ніж можна подумати. Помістіть ваші клітини в NIB (або дошки розкадрувань) та закріпіть їх, щоб автоматична компоновка виконала всю роботу

Враховуючи таку структуру:

TableView

TableViewCell

CollectionView

CollectionViewCell

CollectionViewCell

CollectionViewCell

[... змінна кількість комірок або різний розмір комірок]

Рішення полягає в тому, щоб сказати автоматичному компонуванню обчислити спочатку розміри collectionViewCell, потім збір перегляду contentSize та використовувати його як розмір вашої комірки. Це метод UIView, який "робить магію":

-(void)systemLayoutSizeFittingSize:(CGSize)targetSize 
     withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority 
           verticalFittingPriority:(UILayoutPriority)verticalFittingPriority

Ви повинні встановити тут розмір TableViewCell, який у вашому випадку є contentSize CollectionView.

CollectionViewCell

У CollectionViewCell вам потрібно повідомити клітинку розташувати щоразу, коли ви змінюєте модель (наприклад: ви встановлюєте UILabel з текстом, тоді клітина повинна бути розміщена знову).

- (void)bindWithModel:(id)model {
    // Do whatever you may need to bind with your data and 
    // tell the collection view cell's contentView to resize
    [self.contentView setNeedsLayout];
}
// Other stuff here...

TableViewCell

TableViewCell робить магію. Він має розетку для колекції collectionView, дозволяє автоматичний макет для комірок collectionView, використовуючи оцінний розмір UICollectionViewFlowLayout .

Тоді фокус полягає у встановленні розміру комірки tableView методом systemLayoutSizeFittingSize ... (ПРИМІТКА: iOS8 або новішої версії)

ПРИМІТКА. Я намагався використовувати метод висоти комірки делегата tableView. -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPathАле це вже занадто пізно, щоб система автоматичного компонування обчислила CollectionView contentSize, і іноді ви можете знайти неправильно змінені комірки.

@implementation TableCell

- (void)awakeFromNib {
    [super awakeFromNib];
    UICollectionViewFlowLayout *flow = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;

    // Configure the collectionView
    flow.minimumInteritemSpacing = ...;

    // This enables the magic of auto layout. 
    // Setting estimatedItemSize different to CGSizeZero 
    // on flow Layout enables auto layout for collectionView cells.
    // https://developer.apple.com/videos/play/wwdc2014-226/
    flow.estimatedItemSize = CGSizeMake(1, 1);

    // Disable the scroll on your collection view
    // to avoid running into multiple scroll issues.
    [self.collectionView setScrollEnabled:NO];
}

- (void)bindWithModel:(id)model {
    // Do your stuff here to configure the tableViewCell
    // Tell the cell to redraw its contentView        
    [self.contentView layoutIfNeeded];
}

// THIS IS THE MOST IMPORTANT METHOD
//
// This method tells the auto layout
// You cannot calculate the collectionView content size in any other place, 
// because you run into race condition issues.
// NOTE: Works for iOS 8 or later
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority {

    // With autolayout enabled on collection view's cells we need to force a collection view relayout with the shown size (width)
    self.collectionView.frame = CGRectMake(0, 0, targetSize.width, MAXFLOAT);
    [self.collectionView layoutIfNeeded];

    // If the cell's size has to be exactly the content 
    // Size of the collection View, just return the
    // collectionViewLayout's collectionViewContentSize.

    return [self.collectionView.collectionViewLayout collectionViewContentSize];
}

// Other stuff here...

@end

TableViewController

Не забудьте ввімкнути систему автоматичного компонування для комірок tableView у вашому TableViewController :

- (void)viewDidLoad {
    [super viewDidLoad];

    // Enable automatic row auto layout calculations        
    self.tableView.rowHeight = UITableViewAutomaticDimension;
    // Set the estimatedRowHeight to a non-0 value to enable auto layout.
    self.tableView.estimatedRowHeight = 10;

}

КРЕДИТ: @rbarbera допоміг розібратися в цьому


4
Так. Це працює. Це має бути прийнятою відповіддю.
csotiriou

1
Чи може будь-який орган надати мені зразок коду для цього? Я хочу показати декілька зображень у вертикальному вигляді колекції, яке знаходиться в осередку tableview.
Ravi Ojha

4
Нарешті це для мене спрацювало, але мені довелося зробити інший трюк: cell.bounds = CGRectMake(0, 0, CGRectGetWidth(tableView.bounds), 10000);це "імітує" довгу клітинку з довгим collectionView, тож collectionView обчислить розмір усіх її комірок. В іншому випадку collectionView обчислює лише видимі розміри комірок і неправильно встановлює висоту talbeViewCell.
ingaham

20
при встановленні висоти кадру максимальною в systemLayoutSizeFittingSize, я стикаюся з проблемою швидко, коли перезавантажуєте клітинку, програми, схоже, застрягли після self.collectionView.layoutIfNeeded(). Я зафіксував це, встановивши висоту рами на 1, а не на максимальну висоту. Сподіваюся, що це допоможе, якщо хтось наткнеться на цю проблему.
титан

6
Ось що для мене виправленоsystemLayoutSizeFittingcollectionView.layoutIfNeeded()collectionView.frame = CGRect.init(origin: .zero, size: CGSize.init(width: targetSize.width, height: 1))
поверніть

101

Я думаю, що моє рішення набагато простіше, ніж рішення, запропоноване @PabloRomeu.

Крок 1. Створіть розетку від UICollectionViewдо UITableViewCell subclass, де UICollectionViewрозміщено. Нехай, це буде ім'яcollectionView

Крок 2. Додайте в IB для UICollectionViewобмеження висоти і також створіть розетку UITableViewCell subclass. Нехай, це буде ім'я collectionViewHeight.

Крок 3. У tableView:cellForRowAtIndexPath:коді додавання:

// deque a cell
cell.frame = tableView.bounds;
[cell layoutIfNeeded];
[cell.collectionView reloadData];
cell.collectionViewHeight.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height;

1
Ви насправді пробували це? Не видається можливим встановити обмеження висоти для подання колекції та закріпити його на полях комірки подання таблиці. У вас є або занадто мало обмежень (отже, попередження про нульовий розмір), або у вас виникають конфліктні обмеження (одне з яких ігнорується). Поясніть, будь ласка, як встановити обмеження для цього рішення.
Дейл

2
У мене це спрацювало. Я додаю обмеження collectionViewна всі сторони UITableViewCellі встановити tableView.estimatedRowHeight = 44;іtableView.rowHeight = UITableViewAutomaticDimension;
Ігор

3
Цей працює як чемпіон ... простий та ефективний ... дякую. Якщо для когось це не працює, можливо, це може бути причиною, нам потрібно прив’язати нижню частину подання колекції до нижньої комірки подання таблиці. Тоді воно почне працювати. Щасливе кодування .. :)
Себін Рой

2
Чи вдасться це працювати, коли змінити розмір екрана, скажімо, обертанням iPad? Це потенційно може змінити висоту подання колекції, а отже, і висоту комірки, але якщо на екрані комірка не обов'язково буде перезавантажена табличним поданням, таким чином, ніколи не викликаючи метод CellForRowAtIndexPath: і не даючи вам шансів на зміна константи обмеження. Хоча можливо примусити reloadData, хоча.
Карл Ліндберг

2
Ви пробували різні розміри комірок collectionView? Це була моя проблема. Якщо у вас різні розміри осередків collectionView, це не спрацювало ... :(
Пабло Ромеу

22

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

Я рекомендую вам використовувати лише представлення колекції для всіх своїх цілей.

Ви можете поділити його на розділи та "трактувати" макет деяких розділів як подання таблиці, а інші - як перегляд колекції. Зрештою, нічого такого, чого ви не можете досягти, перегляньте колекцію, яку ви можете зробити із поданням таблиці.

Якщо у вас є базовий макет сітки для "деталей" у вашій колекції, ви можете також використовувати звичайні комірки таблиці для обробки. Однак якщо вам не потрібна підтримка iOS 5, краще використовувати представлення колекцій.


1
Ви поставили "лікувати" в лапки, тому що ви НЕ можете визначати різні макети на розділ CollectionView, правда? Я не знайшов можливості визначити різні макети для різних розділів перегляду колекцій. Я щось не помічаю, чи ти говориш про те, що по-різному реагую на "layoutAttributesForItemAtIndexPath" для різних розділів мого власного підкласу UICollectionViewLayout?
alex da franca

Так -> Ви говорите про те, як реагувати по-різному на layoutAttributesForItemAtIndexPathрізні розділи мого власного спеціального підкласу UICollectionViewLayout?
Рівера

2
@Rivera, ваша відповідь найбільш розумна і звучить просто правильно. Я читав цю пропозицію в багатьох місцях. Чи можете ви також поділитися деяким посиланням на вибірку чи довідку про те, як це досягти чи принаймні деякі покажчики. TIA
підписання

3
Ваша відповідь передбачає, що ви починаєте з нуля і не маєте великого складного перегляду таблиці, в який вам потрібно вписатись. Питання спеціально задалося про те, як розмістити перегляд колекції в табличному перегляді. IMO ваша відповідь не є "відповіддю"
xaphod

2
Це погана відповідь. Мати перегляди колекції всередині представлень таблиць - це звичайна річ, майже кожен додаток робить це.
аварійний збір777

10

Відповідь Пабло Ромеу вище ( https://stackoverflow.com/a/33364092/2704206 ) надзвичайно допомогла мені у питанні. Мені довелося зробити кілька справ по-різному, однак для того, щоб я працював над своєю проблемою. По-перше, мені не довелося дзвонити layoutIfNeeded()так часто. Мені довелося лише викликати це collectionViewу systemLayoutSizeFittingфункції.

По-друге, я мав обмеження щодо автоматичного компонування на моєму перегляді колекції в комірці подання таблиці, щоб надати йому деяку підкладку. Тож мені довелося відняти провідні та кінцеві поля від targetSize.widthвстановлення collectionView.frameширини. Я також повинен був додати верхній і нижній поля до CGSizeвисоти повернення .

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

class CollectionTableViewCell: UITableViewCell {

    // MARK: -
    // MARK: Properties
    @IBOutlet weak var collectionView: UICollectionView! {
        didSet {
            collectionViewLayout?.estimatedItemSize = CGSize(width: 1, height: 1)
            selectionStyle = .none
        }
    }

    var collectionViewLayout: UICollectionViewFlowLayout? {
        return collectionView.collectionViewLayout as? UICollectionViewFlowLayout
    }

    // MARK: -
    // MARK: UIView functions
    override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
        collectionView.layoutIfNeeded()

        let topConstraintConstant = contentView.constraint(byIdentifier: "topAnchor")?.constant ?? 0
        let bottomConstraintConstant = contentView.constraint(byIdentifier: "bottomAnchor")?.constant ?? 0
        let trailingConstraintConstant = contentView.constraint(byIdentifier: "trailingAnchor")?.constant ?? 0
        let leadingConstraintConstant = contentView.constraint(byIdentifier: "leadingAnchor")?.constant ?? 0

        collectionView.frame = CGRect(x: 0, y: 0, width: targetSize.width - trailingConstraintConstant - leadingConstraintConstant, height: 1)

        let size = collectionView.collectionViewLayout.collectionViewContentSize
        let newSize = CGSize(width: size.width, height: size.height + topConstraintConstant + bottomConstraintConstant)
        return newSize
    }
}

Як допоміжна функція для отримання обмеження за ідентифікатором, я додаю таке розширення:

extension UIView {
    func constraint(byIdentifier identifier: String) -> NSLayoutConstraint? {
        return constraints.first(where: { $0.identifier == identifier })
    }
}

ПРИМІТКА. Вам потрібно буде встановити ідентифікатор цих обмежень у вашій дошці даних або в тому місці, де вони створюються. Якщо вони не мають константу 0, це не має значення. Також, як і у відповіді Пабло, вам потрібно буде використовувати UICollectionViewFlowLayoutяк макет для подання вашої колекції. Нарешті, переконайтеся, що ви пов’язали collectionViewIBOutlet зі своєю дошкою.

Маючи спеціальну комірку перегляду таблиць вище, я тепер можу підкласифікувати її в будь-яку іншу клітинку подання таблиці, яка потребує перегляду колекції, і надати їй реалізацію UICollectionViewDelegateFlowLayoutта UICollectionViewDataSourceпротоколи. Сподіваюся, це корисно комусь іншому!


5

Я читав усі відповіді. Це, здається, служить для всіх справ.

override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
        collectionView.layoutIfNeeded()
        collectionView.frame = CGRect(x: 0, y: 0, width: targetSize.width , height: 1)
        return collectionView.collectionViewLayout.collectionViewContentSize
}

3

Альтернативою рішення Пабло Ромеу є налаштування самого UICollectionView, а не виконання роботи в комірці перегляду таблиці.

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

Створіть підклас UICollectionView та замініть такі методи

override func intrinsicContentSize() -> CGSize {
    self.layoutIfNeeded()

    var size = super.contentSize
    if size.width == 0 || size.height == 0 {
        // return a default size
        size = CGSize(width: 600, height:44)
    }

    return size
 }

override func reloadData() {
    super.reloadData()
    self.layoutIfNeeded()
    self.invalidateIntrinsicContentSize()
}

(Вам також слід перекрити відповідні методи: reloadSections, reloadItemsAtIndexPaths аналогічно reloadData ())

Виклик layoutIfNeeded змушує представлення колекції перерахувати розмір вмісту, який потім може бути використаний як новий внутрішній розмір.

Також потрібно чітко обробити зміни розміру перегляду (наприклад, при обертанні пристрою) в контролері подання таблиці

    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
{
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    dispatch_async(dispatch_get_main_queue()) {
        self.tableView.reloadData()
    }
}

брато, чи можете ви допомогти моїй проблемі stackoverflow.com/questions/44650058/… ?
Травень Фію

3

Нещодавно я стикався з тим самим питанням, і я майже спробував кожне рішення у відповідях, деякі з них спрацювали, а інші не моє головне занепокоєння щодо підходу @PabloRomeu - це те, що якщо у вас є інший вміст у комірці (крім огляду колекції) вам доведеться обчислити їх висоту та висоту обмежень і повернути результат, щоб правильно встановити автоматичний макет, і я не люблю обчислювати речі вручну в коді. Тож ось рішення, яке працювало для мене чудово, не роблячи в коді ніяких ручних розрахунків.

у cellForRow:atIndexPathподанні таблиці я виконую наступне:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //do dequeue stuff
    //initialize the the collection view data source with the data
    cell.frame = CGRect.zero
    cell.layoutIfNeeded()
    return cell
}

Я думаю, що тут відбувається те, що я змушую комірку tableview відрегулювати її висоту після розрахунку висоти подання колекції. (після надання дати колекціїView джерелу даних)


2

Я ставлю статичний метод на клас перегляду колекції, який повертає розмір на основі вмісту, який він буде мати. Потім використовуйте цей метод у, heightForRowAtIndexPathщоб повернути належний розмір.

Також зауважте, що ви можете проявляти дивну поведінку, коли вставляєте такі види виду контролю. Я робив це один раз і мав деякі дивні проблеми з пам’яттю, які я ніколи не працював.


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

2

Можливо, мій варіант буде корисний; я вирішував це завдання протягом двох останніх годин. Я не прикидаюсь, що це на 100% правильно чи оптимально, але моя майстерність ще дуже мала, і я хотів би почути коментарі експертів. Дякую. Одне важливе зауваження: це працює для статичної таблиці - це визначено моєю поточною роботою. Таким чином, всі використовують я це viewWillLayoutSubviews з Tableview . І ще трохи.

private var iconsCellHeight: CGFloat = 500 

func updateTable(table: UITableView, withDuration duration: NSTimeInterval) {
    UIView.animateWithDuration(duration, animations: { () -> Void in
        table.beginUpdates()
        table.endUpdates()
    })
}

override func viewWillLayoutSubviews() {
    if let iconsCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 1)) as? CategoryCardIconsCell {
        let collectionViewContentHeight = iconsCell.iconsCollectionView.contentSize.height
        if collectionViewContentHeight + 17 != iconsCellHeight {
            iconsCellHeight = collectionViewContentHeight + 17
            updateTable(tableView, withDuration: 0.2)
        }
    }
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    switch (indexPath.section, indexPath.row) {
        case ...
        case (1,0):
            return iconsCellHeight
        default:
            return tableView.rowHeight
    }
}
  1. Я знаю, що collectionView розташований у першому рядку другого розділу;
  2. Нехай висота ряду дорівнює 17 п. більший, ніж його вміст, висота;
  3. iconsCellHeight - випадкове число, коли програма починається (я знаю, що в портретній формі воно повинно бути рівно 392, але це не важливо). Якщо вміст collectionView + 17 не дорівнює цьому числу, то змініть його значення. Наступного разу в цій ситуації умова надає НЕБУДЬ;
  4. Зрештою оновіть tableView. У моєму випадку це поєднання двох операцій (для приємного оновлення розширюваних рядків);
  5. І звичайно, у висотуForRowAtIndexPath додати один код до коду.

2

Найпростіший підхід, який я придумав, до цих пір "Подяки" @igor відповідь вище

У вашому класі tableviewcell просто вставте це

override func layoutSubviews() {
    self.collectionViewOutlet.constant = self.postPoll.collectionViewLayout.collectionViewContentSize.height
}

і, звичайно, змінити колекціюviewoutlet з розеткою в класі комірки


1
Висота клітини не обчислюється належним чином
Нік Ков

2

Я отримую ідею від посту @Igor і швидко вкладаю свій час у цей проект

Просто минуле це у вашому

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //do dequeue stuff
    cell.frame = tableView.bounds
    cell.layoutIfNeeded()
    cell.collectionView.reloadData()
    cell.collectionView.heightAnchor.constraint(equalToConstant: cell.collectionView.collectionViewLayout.collectionViewContentSize.height)
    cell.layoutIfNeeded()
    return cell
}

Доповнення: Якщо під час завантаження комірок ви бачите, що ваш UICollectionView хопливий.

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {       
  //do dequeue stuff
  cell.layer.shouldRasterize = true
  cell.layer.rasterizationScale = UIScreen.main.scale
  return cell
}

0

Рішення Пабло не дуже добре працювало для мене, у мене були дивні візуальні ефекти (колекціяView не налаштована правильно).

Насправді було налаштувати обмеження висоти collectionView (як NSLayoutConstraint) на колекцію contentView contentSize протягом layoutSubviews(). Це метод, який називається при застосуванні автоматичної розстановки до комірки.

// Constraint on the collectionView height in the storyboard. Priority set to 999.
@IBOutlet weak var collectionViewHeightConstraint: NSLayoutConstraint!


// Method called by autolayout to layout the subviews (including the collectionView).
// This is triggered with 'layoutIfNeeded()', or by the viewController
// (happens between 'viewWillLayoutSubviews()' and 'viewDidLayoutSubviews()'.
override func layoutSubviews() {

    collectionViewHeightConstraint.constant = collectionView.contentSize.height
    super.layoutSubviews()
}

// Call `layoutIfNeeded()` when you update your UI from the model to trigger 'layoutSubviews()'
private func updateUI() {
    layoutIfNeeded()
}

-3

У вашому UITableViewDelegate:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return ceil(itemCount/4.0f)*collectionViewCellHeight;
}

Замініть itemCount і CollectionViewCellHeight реальними значеннями. Якщо у вас є масив масивів itemCount може бути:

self.items[indexPath.row].count

Або що завгодно.


Я думаю, що головне питання полягає в тому, як зробити розрахунок collectionViewCellHeight до того, як він вийде.
підписання

-3

1.Створіть пустушку клітинку.
2. Використовуйте метод collectionViewContentSize на UICollectionViewLayout UICollectionView з використанням поточних даних.


Це має бути найкращою відповіддю ... оскільки немає можливості встановити висоту комірки за допомогою "uicollectionview", не розміщуючи вміст у макетній комірці, отримати висоту, а потім знову встановити її у відповідну клітинку
Bartłomiej Semańczyk

як я можу використовувати цей метод?
xtrinch

Додайте приклад.
Нік Ков

-5

Ви можете розрахувати висоту колекції на основі його властивостей , таких як itemSize, sectionInset, minimumLineSpacing, minimumInteritemSpacing, якщо ваші collectionViewCellмають кордон правила.

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