คุณสามารถเคลื่อนไหวความสูงเปลี่ยนแปลงบน UITableViewCell เมื่อเลือกได้หรือไม่?


393

ฉันใช้UITableViewแอพใน iPhone และมีรายชื่อคนที่อยู่ในกลุ่ม ฉันต้องการมันเพื่อที่ว่าเมื่อผู้ใช้คลิกที่บุคคลใดบุคคลหนึ่ง (เช่นการเลือกเซลล์) เซลล์จะเพิ่มความสูงเพื่อแสดงตัวควบคุม UI หลายตัวเพื่อแก้ไขคุณสมบัติของบุคคลนั้น

เป็นไปได้ไหม

คำตอบ:


879

ฉันพบวิธีแก้ปัญหาที่ง่ายมาก ๆ สำหรับเรื่องนี้ซึ่งเป็นผลข้างเคียงจากการUITableViewทำงานของฉัน .....

จัดเก็บความสูงของเซลล์ในตัวแปรที่รายงานความสูงดั้งเดิมตามปกติผ่านทางtableView: heightForRowAtIndexPath:จากนั้นเมื่อคุณต้องการทำให้ความสูงเปลี่ยนแปลงนั้นเพียงแค่เปลี่ยนค่าของตัวแปรและเรียกสิ่งนี้ว่า ...

[tableView beginUpdates];
[tableView endUpdates];

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

ฉันมีคำอธิบายโดยละเอียดและตัวอย่างโค้ดแบบเต็มในบล็อกของฉัน ... Animate UITableView Cell Height Change


6
อันนี้ยอดเยี่ยม แต่มีวิธีใดบ้างที่เราสามารถควบคุมความเร็วการเคลื่อนไหวของตารางได้?
Josh Kahane

7
มันใช้งานได้ แต่ถ้าฉันทำให้เซลล์มีขนาดใหญ่ขึ้นให้บอกว่า 44 - 74 แล้วทำให้มันเล็กลงอีกถึง 44 เส้นคั่นทำหน้าที่แปลกโดยสิ้นเชิง บางคนยืนยันได้ไหม
plaetzchen

46
นี่เป็นโซลูชันที่แปลกประหลาด แต่เป็นสิ่งที่ Apple แนะนำในเซสชัน "มุมมองตารางการควบคุม" ของ WWDC 2010 เช่นกัน ฉันจะส่งรายงานข้อผิดพลาดเกี่ยวกับการเพิ่มลงในเอกสารประกอบเพราะฉันเพิ่งใช้เวลาค้นคว้าประมาณ 2 ชั่วโมง
bpapa

5
ฉันได้ลองใช้วิธีแก้ปัญหานี้แล้วและบางครั้งก็ใช้งานได้เมื่อคุณกดเซลล์มีโอกาส 50% ที่จะทำงาน ใครมีข้อผิดพลาดที่เหมือนกันหรือไม่ มันเป็นเพราะ iOS7?
Joan Cardona

7
ตอนนี้มันเขียนไว้ในเอกสารอย่างเป็นทางการ: You can also use this method followed by the endUpdates method to animate the change in the row heights without reloading the cell. developer.apple.com/library/ios/documentation/UIKit/Reference/
......

63

ฉันชอบคำตอบของ Simon Lee ฉันไม่ได้ลองวิธีนี้ แต่ดูเหมือนว่ามันจะเปลี่ยนขนาดของเซลล์ทั้งหมดในรายการ ฉันหวังว่าจะมีการเปลี่ยนแปลงเพียงเซลล์ที่แตะอยู่ ฉันชอบ Simon แต่มีความแตกต่างเล็กน้อย สิ่งนี้จะเปลี่ยนรูปลักษณ์ของเซลล์เมื่อมีการเลือก และมันก็ทำให้เคลื่อนไหว เป็นอีกวิธีในการทำ

สร้าง int เพื่อเก็บค่าสำหรับดัชนีเซลล์ที่เลือกในปัจจุบัน:

int currentSelection;

แล้ว:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    int row = [indexPath row];
    selectedNumber = row;
    [tableView beginUpdates];
    [tableView endUpdates];
}

แล้ว:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    if ([indexPath row] == currentSelection) {
        return  80;
    }
    else return 40;


}

ฉันแน่ใจว่าคุณสามารถทำการเปลี่ยนแปลงที่คล้ายกันใน tableView: cellForRowAtIndexPath: เพื่อเปลี่ยนประเภทของเซลล์หรือแม้แต่การโหลดไฟล์ xib สำหรับเซลล์

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


2
ตรวจสอบรหัสที่แนบมากับโพสต์ของฉันฉันทำอย่างนี้เพิ่มความสูงเป็นสองเท่าสำหรับเซลล์เมื่อเลือก :)
Simon Lee

8
"ฉันไม่ได้ลองวิธีนี้ แต่ดูเหมือนว่ามันจะเปลี่ยนขนาดของเซลล์ทั้งหมดในรายการ" - จากนั้นคุณไม่ได้ดูยากมาก
jamie

13
การเลือกปัจจุบันถูกเก็บไว้ใน tableView.indexPathForSelectedRow
นิค

22

เพิ่มคุณสมบัติเพื่อติดตามเซลล์ที่เลือก

@property (nonatomic) int currentSelection;

ตั้งค่าเป็นค่า Sentinel ใน (ตัวอย่าง) viewDidLoadเพื่อให้แน่ใจว่าการUITableViewเริ่มต้นในตำแหน่ง 'ปกติ'

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    //sentinel
    self.currentSelection = -1;
}

ในheightForRowAtIndexPathคุณสามารถตั้งค่าความสูงที่คุณต้องการสำหรับเซลล์ที่เลือก

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    int rowHeight;
    if ([indexPath row] == self.currentSelection) {
        rowHeight = self.newCellHeight;
    } else rowHeight = 57.0f;
    return rowHeight;
}

ในdidSelectRowAtIndexPathคุณบันทึกการเลือกปัจจุบันและบันทึกความสูงแบบไดนามิกถ้าจำเป็น

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        // do things with your cell here

        // set selection
        self.currentSelection = indexPath.row;
        // save height for full text label
        self.newCellHeight = cell.titleLbl.frame.size.height + cell.descriptionLbl.frame.size.height + 10;

        // animate
        [tableView beginUpdates];
        [tableView endUpdates];
    }
}

ในการdidDeselectRowAtIndexPathตั้งค่าดัชนีการเลือกกลับไปที่ค่าแมวมองและเคลื่อนไหวเซลล์กลับสู่รูปแบบปกติ

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {       
        // do things with your cell here

        // sentinel
        self.currentSelection = -1;

        // animate
        [tableView beginUpdates];
        [tableView endUpdates];
    }
}

ขอบคุณขอบคุณขอบคุณ! ฉันเพิ่มรหัสเล็กน้อยเพื่อให้เซลล์สลับได้ ฉันเพิ่มรหัสด้านล่าง
ก.ย.

14

reloadData ไม่ดีเพราะไม่มีภาพเคลื่อนไหว ...

นี่คือสิ่งที่ฉันกำลังพยายาม:

NSArray* paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView deleteRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];

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


โดยส่วนตัวแล้วฉันพบว่าการใช้วิธีนี้ แต่ด้วย UITableViewRowAnimationNone จะให้ผลลัพธ์ที่ราบรื่นกว่า แต่ก็ยังไม่สมบูรณ์แบบ
Ron Srebro

11

ฉันไม่รู้ว่าทุกอย่างเกี่ยวกับการเรียก startUpdates / endUpdates นี้คืออะไรคุณสามารถใช้งาน-[UITableView reloadRowsAtIndexPaths:withAnimation:]ได้ นี่เป็นโครงการตัวอย่าง


ยอดเยี่ยมสิ่งนี้ไม่ยืดมุมมองข้อความของฉันในเซลล์เค้าโครงอัตโนมัติ แต่มันจะต้องมีการสั่นไหวไปยังภาพเคลื่อนไหวเพราะตัวเลือกไม่มีภาพเคลื่อนไหวมีความผิดพลาดเมื่อทำการอัพเดตขนาดของเซลล์
h3dkandi

10

reloadRowsAtIndexPathsฉันแก้ไขด้วย

ฉันบันทึกในdidSelectRowAtIndexPathindexPath ของเซลล์ที่เลือกและเรียกใช้reloadRowsAtIndexPathsที่ส่วนท้าย (คุณสามารถส่ง NSMutableArray สำหรับรายการองค์ประกอบที่คุณต้องการโหลดซ้ำ)

ในheightForRowAtIndexPathคุณสามารถตรวจสอบว่า indexPath อยู่ในรายการหรือไม่ของเซลล์ expandIndexPath และส่งความสูง

คุณสามารถตรวจสอบตัวอย่างพื้นฐานนี้: https://github.com/ferminhg/iOS-Examples/tree/master/iOS-UITableView-Cell-Height-Change/celdascambiadetam มันเป็นวิธีง่ายๆ

ฉันเพิ่มรหัสประเภทถ้าช่วยคุณ

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 20;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath*)indexPath
{
    if ([indexPath isEqual:_expandIndexPath])
        return 80;

    return 40;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Celda";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    [cell.textLabel setText:@"wopwop"];

    return cell;
}

#pragma mark -
#pragma mark Tableview Delegate Methods

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSMutableArray *modifiedRows = [NSMutableArray array];
    // Deselect cell
    [tableView deselectRowAtIndexPath:indexPath animated:TRUE];
    _expandIndexPath = indexPath;
    [modifiedRows addObject:indexPath];

    // This will animate updating the row sizes
    [tableView reloadRowsAtIndexPaths:modifiedRows withRowAnimation:UITableViewRowAnimationAutomatic];
}

8

แทนที่จะเป็นbeginUpdates()/ endUpdates()การโทรที่แนะนำตอนนี้:

tableView.performBatchUpdates(nil, completion: nil)

Apple บอกว่าเกี่ยวกับ startUpdates / endUpdates: "ใช้เมธอด performBatchUpdates (_: เสร็จสมบูรณ์ :) :) แทนที่จะเป็นแบบนี้ทุกครั้งที่ทำได้"

ดู: https://developer.apple.com/documentation/uikit/uitableview/1614908-beginupdates


3

ลองทำสิ่งนี้เพื่อขยายแถวดัชนี:

@property (nonatomic) NSIndexPath *expandIndexPath;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
if ([indexPath isEqual:self.expandedIndexPath])
    return 100;

return 44;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *modifiedRows = [NSMutableArray array];
if ([indexPath isEqual:self.expandIndexPath]) {
    [modifiedRows addObject:self.expandIndexPath];
    self.expandIndexPath = nil;
} else {
    if (self.expandedIndexPath)
        [modifiedRows addObject:self.expandIndexPath];

    self.expandIndexPath = indexPath;
    [modifiedRows addObject:indexPath];
}

// This will animate updating the row sizes
[tableView reloadRowsAtIndexPaths:modifiedRows withRowAnimation:UITableViewRowAnimationAutomatic];

// Preserve the deselection animation (if desired)
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ViewControllerCellReuseIdentifier];
    cell.textLabel.text = [NSString stringWithFormat:@"I'm cell %ld:%ld", (long)indexPath.section, (long)indexPath.row];

return cell;
}

3
BOOL flag;

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    flag = !flag;
    [tableView beginUpdates];
    [tableView reloadRowsAtIndexPaths:@[indexPath] 
                     withRowAnimation:UITableViewRowAnimationAutomatic];
    [tableView endUpdates];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES == flag ? 20 : 40;
}

2

แค่โน้ตสำหรับคนอย่างฉันที่กำลังค้นหาเพิ่ม "รายละเอียดเพิ่มเติม" ในเซลล์ที่กำหนดเอง

[tableView beginUpdates];
[tableView endUpdates];

ทำได้ดีมาก แต่อย่าลืมดูเซลล์ "ครอบตัด" จาก Interface Builder เลือกมือถือของคุณ -> ดูเนื้อหา -> จากการตรวจสอบทรัพย์สินเลือก " คลิป subview "


2

Simons รุ่นที่สั้นกว่าตอบสำหรับ Swift 3 และอนุญาตให้สลับการเลือกเซลล์

var cellIsSelected: IndexPath?


  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    cellIsSelected = cellIsSelected == indexPath ? nil : indexPath
    tableView.beginUpdates()
    tableView.endUpdates()
  }


  func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if cellIsSelected == indexPath {
      return 250
    }
    return 65
  }

2

Swift 4 and above

เพิ่มโค้ดด้านล่างลงในวิธีการมอบสิทธิ์แบบแถวของคุณใน tableview

tableView.beginUpdates()
tableView.setNeedsLayout()
tableView.endUpdates()

1

คำตอบของ Simon Lee รุ่นที่รวดเร็ว

// MARK: - Variables 
  var isCcBccSelected = false // To toggle Bcc.



    // MARK: UITableViewDelegate
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {

    // Hide the Bcc Text Field , until CC gets focused in didSelectRowAtIndexPath()
    if self.cellTypes[indexPath.row] == CellType.Bcc {
        if (isCcBccSelected) {
            return 44
        } else {
            return 0
        }
    }

    return 44.0
}

จากนั้นใน didSelectRowAtIndexPath ()

  func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    self.tableView.deselectRowAtIndexPath(indexPath, animated: true)

    // To Get the Focus of CC, so that we can expand Bcc
    if self.cellTypes[indexPath.row] == CellType.Cc {

        if let cell = tableView.cellForRowAtIndexPath(indexPath) as? RecipientTableViewCell {

            if cell.tag == 1 {
                cell.recipientTypeLabel.text = "Cc:"
                cell.recipientTextField.userInteractionEnabled = true
                cell.recipientTextField.becomeFirstResponder()

                isCcBccSelected = true

                tableView.beginUpdates()
                tableView.endUpdates()
            }
        }
    }
}

1

ใช่มันเป็นไปได้

UITableView มีวิธีการมอบหมาย didSelectRowAtIndexPath

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [UIView animateWithDuration:.6
                          delay:0
         usingSpringWithDamping:UIViewAnimationOptionBeginFromCurrentState
          initialSpringVelocity:0
                        options:UIViewAnimationOptionBeginFromCurrentState animations:^{

                            cellindex = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
                            NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil];
                            [violatedTableView beginUpdates];
                            [violatedTableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationAutomatic];
                            [violatedTableView endUpdates];
                        }
                     completion:^(BOOL finished) {
    }];
}

แต่ในกรณีของคุณหากผู้ใช้เลื่อนและเลือกเซลล์อื่นคุณต้องมีเซลล์ที่เลือกล่าสุดเพื่อย่อและขยายการreloadRowsAtIndexPaths:เรียกเซลล์ที่เลือกในปัจจุบันheightForRowAtIndexPath:ดังนั้นจัดการให้สอดคล้อง


0

นี่คือรหัสของUITableViewคลาสย่อยที่กำหนดเองซึ่งขยายUITextViewที่เซลล์ตารางโดยไม่ต้องโหลดซ้ำ (และโฟกัสของแป้นพิมพ์หายไป):

- (void)textViewDidChange:(UITextView *)textView {
    CGFloat textHeight = [textView sizeThatFits:CGSizeMake(self.width, MAXFLOAT)].height;
    // Check, if text height changed
    if (self.previousTextHeight != textHeight && self.previousTextHeight > 0) {
        [self beginUpdates];

        // Calculate difference in height
        CGFloat difference = textHeight - self.previousTextHeight;

        // Update currently editing cell's height
        CGRect editingCellFrame = self.editingCell.frame;
        editingCellFrame.size.height += difference;
        self.editingCell.frame = editingCellFrame;

        // Update UITableView contentSize
        self.contentSize = CGSizeMake(self.contentSize.width, self.contentSize.height + difference);

        // Scroll to bottom if cell is at the end of the table
        if (self.editingNoteInEndOfTable) {
            self.contentOffset = CGPointMake(self.contentOffset.x, self.contentOffset.y + difference);
        } else {
            // Update all next to editing cells
            NSInteger editingCellIndex = [self.visibleCells indexOfObject:self.editingCell];
            for (NSInteger i = editingCellIndex; i < self.visibleCells.count; i++) {
                UITableViewCell *cell = self.visibleCells[i];
                CGRect cellFrame = cell.frame;
                cellFrame.origin.y += difference;
                cell.frame = cellFrame;
            }
        }
        [self endUpdates];
    }
    self.previousTextHeight = textHeight;
}

0

ฉันใช้คำตอบที่ยอดเยี่ยมของ @ Joy และมันทำงานได้อย่างสมบูรณ์กับ ios 8.4 และ XCode 7.1.1

ในกรณีที่คุณต้องการทำให้เซลล์ของคุณสลับได้ฉันเปลี่ยน -tableViewDidSelect เป็นต่อไปนี้:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//This is the bit I changed, so that if tapped once on the cell, 
//cell is expanded. If tapped again on the same cell, 
//cell is collapsed. 
    if (self.currentSelection==indexPath.row) {
        self.currentSelection = -1;
    }else{
        self.currentSelection = indexPath.row;
    }
        // animate
        [tableView beginUpdates];
        [tableView endUpdates];

}

ฉันหวังว่าสิ่งนี้จะช่วยคุณได้


0

ตรวจสอบวิธีนี้หลังจาก iOS 7 และใหม่กว่า

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return UITableViewAutomaticDimension;
}

มีการปรับปรุงสิ่งนี้ใน iOS 8 เราสามารถตั้งค่าเป็นคุณสมบัติของมุมมองตารางได้



0

อินพุต -

tableView.beginUpdates () tableView.endUpdates () ฟังก์ชั่นเหล่านี้จะไม่เรียก

func tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {}

แต่ถ้าคุณทำ tableView.reloadRows (ที่: [selectedIndexPath! as IndexPath], ด้วย: .none)

มันจะเรียก func tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {} ฟังก์ชันนี้


-1

ฉันเพิ่งแก้ไขปัญหานี้ด้วยการแฮ็คเล็กน้อย:

static int s_CellHeight = 30;
static int s_CellHeightEditing = 60;

- (void)onTimer {
    cellHeight++;
    [tableView reloadData];
    if (cellHeight < s_CellHeightEditing)
        heightAnimationTimer = [[NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:@selector(onTimer) userInfo:nil repeats:NO] retain];
}

- (CGFloat)tableView:(UITableView *)_tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
        if (isInEdit) {
            return cellHeight;
        }
        cellHeight = s_CellHeight;
        return s_CellHeight;
}

เมื่อฉันต้องการขยายความสูงของเซลล์ที่ฉันตั้งค่าisInEdit = YESและเรียกใช้เมธอด[self onTimer]และมันจะสร้างการเติบโตของเซลล์จนกว่าจะถึงค่า s_CellHeightEditing :-)


ในการจำลองใช้งานได้ดี แต่ในฮาร์ดแวร์ iPhone จะล่าช้า ด้วยความล่าช้าของตัวจับเวลา 0.05 และด้วยความสูงของเซลล์ที่เพิ่มขึ้น 5 หน่วยมันจะดีกว่ามาก แต่ไม่มีอะไรที่เหมือนกับ CoreAnimation
Dzamir

1
ยืนยันก่อนโพสต์ .. ต่อไป
ajay_nasa

-2

รับพา ธ ดัชนีของแถวที่เลือก รีโหลดตาราง ในเมธอด heightForRowAtIndexPath ของ UITableViewDelegate ให้ตั้งค่าความสูงของแถวที่เลือกเป็นความสูงที่แตกต่างกันและสำหรับวิธีอื่นให้ส่งกลับความสูงของแถวปกติ


2
-1 ไม่ทำงาน [table reloadData]ผลการโทรในการเปลี่ยนแปลงความสูงเกิดขึ้นทันทีแทนที่จะเคลื่อนไหว
Mark Amery
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.