UITableview: วิธีปิดใช้งานการเลือกสำหรับแถวบางรายการ แต่ไม่ใช่อื่น ๆ


298

ฉันกำลังแสดงในtableviewเนื้อหากลุ่มแยกวิเคราะห์จาก XML ฉันต้องการปิดการใช้งานคลิกเหตุการณ์ (ฉันไม่ควรคลิกเลย) ตารางมีสองกลุ่ม ฉันต้องการปิดใช้งานการเลือกสำหรับกลุ่มแรกเท่านั้น แต่ไม่ใช่กลุ่มที่สอง คลิกแถวแรกของกลุ่มที่สองnavigatesไปยังหลอดของฉันplayer viewไปยังหลอดของฉัน

ฉันจะทำให้เลือกเฉพาะกลุ่มหรือแถวได้อย่างไร

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    if(indexPath.section!=0)
    if(indexPath.row==0)    

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:tubeUrl]];   
}

ขอบคุณ

คำตอบ:


499

คุณต้องใส่รหัสนี้ลงไป cellForRowAtIndexPath

วิธีปิดใช้งานคุณสมบัติการเลือกของเซลล์: (ในขณะที่แตะเซลล์)

cell.selectionStyle = UITableViewCellSelectionStyleNone;

วิธีเปิดใช้งานความสามารถในการเลือก (แตะ) เซลล์: (แตะเซลล์)

// Default style
cell.selectionStyle = UITableViewCellSelectionStyleBlue;

// Gray style
cell.selectionStyle = UITableViewCellSelectionStyleGray;

โปรดทราบว่าเซลล์ที่มีselectionStyle = UITableViewCellSelectionStyleNone;จะยังคงทำให้ UI ที่จะโทรdidSelectRowAtIndexPathเมื่อผู้ใช้สัมผัส เพื่อหลีกเลี่ยงปัญหานี้ให้ทำตามคำแนะนำด้านล่างและตั้งค่า

cell.userInteractionEnabled = NO;

แทน. นอกจากนี้โปรดทราบว่าคุณอาจต้องการกำหนดcell.textLabel.enabled = NO;ให้รายการเป็นสีเทา


1
วิธีนี้จะสร้างบั๊กหากคุณพยายามรูดเพื่อลบ
Vive

116
นี่คือแฮ็ค! ทำอย่างนั้นใช้คำตอบด้านล่าง - ใช้ willSelectRowAtIndexPath ด้วยการคืนค่าศูนย์!
Peter Stajger

4
สิ่ง userInteractionEnabled ไม่ถูกต้องขอใช้ willSelectRowAtIndexPath แทนที่จะเป็นบุคคลอื่น
Jonny

23
บน iOS 6.0 และใหม่กว่าtableView:shouldHighlightRowAtIndexPath:เป็นUITableViewDelegateวิธีการใหม่ที่ส่งคืนค่าที่BOOLอ้างอิงว่าindexPathควรผ่านการเน้นสีหรือไม่ หากคุณกำลังสร้าง 6.0 และใหม่กว่าฉันขอแนะนำ API ใหม่นี้อย่างยิ่ง
cbowns

3
หากคุณกำลังทำสิ่งนี้ใน Swift และคุณมีปัญหา แต่จบลงที่นี่คุณจะต้องตั้งค่าcell!.selectionStyle = .Noneที่บังคับให้เซลล์คลายเซลล์เพื่อให้คุณสามารถเข้าถึงคุณสมบัติได้
Marcos

371

หากคุณต้องการสร้างแถว (หรือชุดย่อยของแถว) ที่ไม่สามารถเลือกได้ให้ใช้UITableViewDelegateวิธีการ-tableView:willSelectRowAtIndexPath:(TechZen ที่กล่าวถึง) หากindexPathควรจะไม่สามารถเลือกได้ผลตอบแทนอย่างอื่นกลับnil indexPathเพื่อให้ได้พฤติกรรมการเลือกเริ่มต้นคุณเพียงแค่ส่งindexPathผ่านไปยังdelegateวิธีการของคุณแต่คุณยังสามารถเปลี่ยนการเลือกแถวได้โดยส่งกลับค่าที่แตกต่างกันindexPathแต่คุณยังสามารถปรับเปลี่ยนการเลือกแถวโดยกลับมาที่แตกต่างกัน

ตัวอย่าง:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // rows in section 0 should not be selectable
    if ( indexPath.section == 0 ) return nil;

    // first 3 rows in any section should not be selectable
    if ( indexPath.row <= 2 ) return nil;

    // By default, allow row to be selected
    return indexPath;
}

2
รายละเอียดเล็กน้อย: คุณพูดถึง <= 2, ไม่ใช่ = <2 แย่จัง! :)
Jonas Byström

23
ฉันต้องการเพิ่มว่านี่เป็นคำตอบที่ถูกต้อง แต่คุณควรตั้งค่า selectionStyle เป็น UITableViewCellSelectionStyleNone ใน cellForRowAtIndexPath ทำไม? เนื่องจากไม่มีรูปแบบการเลือกนี้เซลล์จะไม่สามารถเลือกได้ แต่จะยังคงแสดง "ตามที่เลือก" เมื่อกดลง (ดังนั้นจึงเปลี่ยนเป็นสีที่เลือกถ้ามีอีกเซลล์หนึ่งสำหรับเซลล์อื่น)
TooManyEduardos

4
สิ่งนี้ควรมี upvotes มากกว่าคำตอบที่ยอมรับ
1244109

2
ฉันคิดว่าเหตุผลหลักที่ไม่ใช่คำตอบที่ยอมรับก็คือเพราะคำตอบที่ยอมรับนั้นง่ายกว่า ในขณะที่ไม่ใช่วิธีที่ดีที่สุดที่จะทำเพราะตารางของคุณจะยังคงเรียก setSelected: ในเซลล์ของคุณมันยังใช้งานได้ด้วยสายตา คำตอบนี้จะใช้งานได้มากขึ้น แต่เป็นวิธีที่เหมาะสมในการทำ (คุณต้องรวม @TooManyEduardos ข้อเสนอแนะเช่นกัน) เพื่อหลีกเลี่ยงผลกระทบที่ไม่คาดคิดจากการเรียกตาราง setSelected: ในเซลล์ของคุณ
Brian Sachetta

ผมชอบคำตอบนี้ แต่ถ้าคุณไม่ต้องการที่จะทำซ้ำตรรกะของคุณใน cellForRowAtIndexPath และ willSelectRowAtIndexPath เพียงตรวจสอบว่า cell.selectionStyle == ใครใน willSelectRowAtIndexPath กลับศูนย์ (ดูคำตอบของฉันด้านล่าง)
เอริค D'Souza

61

เริ่มต้นใน iOS 6 คุณสามารถใช้

-tableView:shouldHighlightRowAtIndexPath:

หากคุณกลับมาNOจะเป็นการปิดใช้งานทั้งการไฮไลต์การเลือกและกระดานเรื่องราวจะกระตุ้นการเชื่อมต่อกับเซลล์นั้น

วิธีการนี้จะถูกเรียกเมื่อการสัมผัสลงมาบนแถว การย้อนกลับNOไปที่ข้อความนั้นจะหยุดกระบวนการการเลือกและไม่ทำให้แถวที่เลือกในปัจจุบันสูญเสียรูปลักษณ์ที่เลือกขณะที่การกดไม่ทำงาน

UITableViewDelegate การอ้างอิงโปรโตคอล


3
ตกลง สำหรับ iOS 7 และสูงกว่านี้ควรเป็นวิธีที่ต้องการ (อันที่จริงแล้วใน iOS 8 วิธีอื่น ๆ นั้นไม่ได้ผลสำหรับฉัน)
race_carr

นี่ควรเป็นคำตอบที่ดีที่สุด
คาเมรอนอี

16

ไม่มีจากคำตอบข้างต้นแก้ปัญหาได้อย่างถูกต้อง เหตุผลก็คือเราต้องการปิดการใช้งานการเลือกเซลล์ แต่ไม่จำเป็นต้องเป็นหน้าย่อยภายในเซลล์

ในกรณีของฉันฉันกำลังนำเสนอ UISwitch ที่อยู่ตรงกลางแถวและฉันต้องการปิดการเลือกสำหรับส่วนที่เหลือของแถว (ซึ่งว่างเปล่า) แต่ไม่ใช่สำหรับสวิตช์! วิธีที่เหมาะสมในการทำเช่นนั้นคือในวิธีการ

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

ที่คำสั่งของแบบฟอร์ม

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

วิธีการซึ่งเป็นการเตรียมเซลล์และไม่อนุญาตให้มีการโต้ตอบกับ UISwitch

ยิ่งกว่านั้นใช้วิธีการ

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

เพื่อยกเลิกการเลือกเซลล์ด้วยคำสั่งของแบบฟอร์ม

[tableView deselectRowAtIndexPath:indexPath animated:NO];

ยังคงแสดงแถวที่ถูกเลือกในขณะที่ผู้ใช้กดบน contentView ดั้งเดิมของเซลล์

แค่สองเซ็นต์ของฉัน ฉันค่อนข้างมั่นใจว่าหลายคนจะพบว่ามีประโยชน์นี้


ตกลง. และไม่มีศูนย์ที่กลับมาwillSelectRowAtIndexPathมีปัญหาเดียวกันจึงไม่สามารถเลือกการดูย่อยได้
jeffjv

โปรดทราบว่าหากคุณมีตารางคงที่คุณสามารถตั้งค่าการเลือกเป็นไม่มีในตัวสร้างส่วนต่อประสานสำหรับเซลล์ที่คุณไม่ต้องการให้สิ่งที่เลือกปรากฏ
jeffjv

11

คุณดักจับการเลือกด้วยวิธีการแหล่งข้อมูลเหล่านี้

 tableView:willSelectRowAtIndexPath: 
 tableView:didSelectRowAtIndexPath: 
 tableView:willDeselectRowAtIndexPath: 
 tableView:didDeselectRowAtIndexPath:

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

น่าเสียดายที่คุณไม่สามารถปิดการเลือกสำหรับส่วนเดียวได้ มันเป็นทั้งโต๊ะหรือไม่มีอะไรเลย

อย่างไรก็ตามคุณสามารถตั้งค่าselectionStyleคุณสมบัติเซลล์ตารางเป็นUITableViewCellSelectionStyleNoneคุณสมบัติการฉันเชื่อว่าจะทำให้การเลือกไม่สามารถมองเห็นได้ รวมกับวิธีการข้างต้นที่ควรทำให้เซลล์ดูเฉื่อยอย่างสมบูรณ์จากมุมมองของผู้ใช้

Edit01:

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

อย่างไรก็ตามคุณทำเช่นนั้นคุณไม่ต้องการให้ผู้ใช้พยายามเลือกแถวและคิดว่าแอพทำงานผิดปกติเพราะแถวไม่ได้ทำอะไรเลย


โปรดอธิบายวิธีการใช้วิธีการเหล่านี้อย่างละเอียดหรือให้ลิงค์โปรแกรมตัวอย่าง
Warrior

2
@Warrior: หากคุณติดตั้ง SDK คุณสามารถเปิด Xcode ไปที่Help -> Developer documentationแล้วคัดลอกชื่อวิธีการเหล่านั้นลงในช่องค้นหาเพื่อดูว่ามันทำงานอย่างไร เอกสารประกอบสำหรับนักพัฒนายังมีรหัสตัวอย่าง
kennytm


9

คุณต้องทำสิ่งต่อไปนี้เพื่อปิดการเลือกเซลล์ภายในcellForRowAtIndexPathวิธี:

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[cell setUserInteractionEnabled:NO];

ในการแสดงเซลล์สีเทาให้ใส่ต่อไปนี้ภายในtableView:WillDisplayCell:forRowAtIndexPathวิธี

[cell setAlpha:0.5];

วิธีหนึ่งช่วยให้คุณควบคุมการโต้ตอบส่วนอีกวิธีหนึ่งช่วยให้คุณควบคุมลักษณะที่ปรากฏของ UI


5

หากต้องการหยุดเพียงบางเซลล์ที่ถูกเลือกให้ใช้:

cell.userInteractionEnabled = NO;

เช่นเดียวกับการป้องกันการเลือกสิ่งนี้จะหยุด tableView: didSelectRowAtIndexPath: ถูกเรียกสำหรับเซลล์ที่ตั้งค่าไว้


1
สิ่งประหลาดเกิดขึ้นตลอดเวลา: เมื่อฉันตั้งค่าuserInteractionEnabledเป็น NO ในเซลล์หนึ่ง (ชัดเจนยิ่งขึ้นหนึ่ง indexPath) การโต้ตอบผู้ใช้ของเซลล์ OTHER บางเซลล์จะถูกปิดการใช้งาน ฉันไม่มีเงื่อนงำว่าทำไมสิ่งนี้เกิดขึ้นทุกครั้งที่ฉันใช้userInteractionEnabledกับเซลล์มุมมองตาราง มันเป็นข้อบกพร่องที่รู้จักหรือฉันทำอะไรผิดพลาด?
Philip007

3
@ Philip007 เซลล์ "NO" ถูกนำกลับมาใช้ใหม่หรือไม่ ถ้าเป็นเช่นนั้นคุณอาจต้องแน่ใจว่าคุณตั้งค่าเป็น "ใช่" เมื่อคุณ dequeue เซลล์
JosephH

1
ทำไมตั้งเป็น "ใช่" ฉันอยากให้มันจะไม่มี (ผู้ใช้ไม่อนุญาต) .. ตัวอย่างทั่วไปคือว่าผมตั้งโต้ตอบกับผู้ใช้ของแถวแรก ( if [indexPath row] == 0) ไปNOในtableView:cellForRowAtIndexPath:หลัง dequeueing เซลล์ โดยปกติจะใช้งานได้ในตอนแรก จากนั้นหลังจากการเรียกหลายครั้งreloadDataทันใดนั้นแถวที่ห้าไม่ได้รับอนุญาตจากนั้นแถวที่สี่ .. ฉันไม่สามารถคิดได้ว่ามันจะเกิดขึ้นเมื่อไหร่ สิ่งทั้งหมดดูสุ่ม
Philip007

6
@ Philip007 หากคุณกำลังนำเซลล์ที่คุณจะต้องตั้งค่าได้ที่ "ใช่" สำหรับเซลล์ที่คุณทำต้องการให้มีการโต้ตอบ มิฉะนั้นหากเซลล์ "ไม่" ถูกนำมาใช้ซ้ำในแถวที่คุณต้องการให้มีการโต้ตอบเซลล์นั้นจะยังคงถูกปิดใช้งาน เช่น:if [indexPath row] == 0) { set to NO } else { set to YES }
JosephH

5

คุณสามารถใช้tableView:willDisplayCellวิธีการปรับแต่งทุกชนิดกับ tableViewCell

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
     [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
     [cell setUserInteractionEnabled:NO];

     if (indexPath.section == 1 && indexPath.row == 0)
     {
         [cell setSelectionStyle:UITableViewCellSelectionStyleGray];
         [cell setUserInteractionEnabled:YES];
     }
} 

ในโค้ดด้านบนนี้ผู้ใช้สามารถเลือกแถวแรกในส่วนที่สองของ tableView เท่านั้น ส่วนที่เหลือทั้งหมดไม่สามารถเลือกได้ ขอบคุณ! ~



5

โซลูชันของฉันใช้แบบจำลองข้อมูล:

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    let rowDetails = viewModel.rowDetails(forIndexPath: indexPath)
    return rowDetails.enabled ? indexPath : nil
}

func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
    let rowDetails = viewModel.rowDetails(forIndexPath: indexPath)
    return rowDetails.enabled
}

5

สำหรับ swift 4.0 นี่จะเป็นการหลอกลวง มันจะปิดการใช้งานเซลล์ในวิธี didSelectRowAtIndexPath แต่ให้คลิกย่อยได้

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
         if (indexPath.row == clickableIndex ) { 
            return indexPath
         }else{
            return nil
        }
    }

หรือสั้น ๆ : return indexPath.row == clickableIndex ? indexPath : nilทำให้โค้ดของคุณสะอาดขึ้น ;-)
ทำเครื่องหมาย

1

ใช้สิ่งนี้เพื่อทำให้เซลล์ดูเหมือนถูกปิดใช้งานและไม่สามารถเลือกได้:

cell.selectionStyle = UITableViewCellSelectionStyleNone;

สำคัญ: โปรดทราบว่านี่เป็นเพียงคุณสมบัติการจัดแต่งทรงผมเท่านั้นและไม่ได้ปิดการใช้งานเซลล์ ในการดำเนินการดังกล่าวคุณต้องตรวจสอบselectionStyleในdidSelectRowAtIndexPath:การติดตั้งผู้รับมอบสิทธิ์ของคุณ:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if(cell.selectionStyle == UITableViewCellSelectionStyleNone) {
        return;
    }

    // do your cell selection handling here
}

1

ฉันชอบคำตอบของ Brian Chapados ด้านบน อย่างไรก็ตามหมายความว่าคุณอาจทำซ้ำตรรกะในทั้ง cellForRowAtIndexPath และจากนั้นจะ willSelectRowAtIndexPath ซึ่งสามารถซิงค์ได้อย่างง่ายดาย แทนที่จะทำตรรกะซ้ำเพียงตรวจสอบ selectionStyle:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if (cell.selectionStyle == UITableViewCellSelectionStyleNone)
        return nil;

    else
        return indexPath;
}

1

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

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if (cell.accessoryType != UITableViewCellAccessoryDisclosureIndicator) {
        return nil;
    }
    return indexPath;
}

1

บน Xcode 7 โดยไม่ต้องเข้ารหัสคุณสามารถทำสิ่งต่อไปนี้ได้:

ในมุมมองเค้าร่างเลือกเซลล์มุมมองตาราง (เซลล์ซ้อนอยู่ใต้ Table Controller Controller Scene> Table View Controller> Table View คุณอาจต้องเปิดเผยวัตถุเหล่านั้นเพื่อดูเซลล์ Table view)

ในตัวตรวจสอบแอตทริบิวต์ให้ค้นหาฟิลด์ที่มีข้อความการเลือกและเลือกไม่มี ตัวตรวจสอบ atribute ด้วยตัวเลือกนี้เซลล์จะไม่ได้รับไฮไลต์ที่มองเห็นเมื่อผู้ใช้แตะมัน


0

SIMPLE

เพียงใช้cell.userInteractionEnabled = YES;กับเซลล์ถ้ามันสามารถนำทางและcell.userInteractionEnabled = NO;อื่น ๆ


1
สิ่งนี้ยังป้องกันการมีปฏิสัมพันธ์กับมุมมองอุปกรณ์เสริมภายในเซลล์ซึ่งอาจไม่ใช่พฤติกรรมที่ต้องการ
เกร็กบราวน์

0

ใช้วิธีการtableView:willSelectRowAtIndexPath: ในแหล่งข้อมูลสำหรับตารางของคุณ ถ้าคุณต้องการแถวที่พา ธ เพื่อไฮไลต์ให้ส่งคืน indexPath ที่กำหนด หากคุณไม่ส่งคืนศูนย์

ตัวอย่างจากแอพของฉัน:

- (NSIndexPath *)tableView:(UITableView *)tableView
    willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    MySelectableObj* obj = [self objectAtPath:indexPath];
    if(obj==nil) return nil;
    return indexPath;
}

สิ่งที่ดีเกี่ยวกับเรื่องนี้คือshouldPerformSegueWithIdentifier:sender:จะไม่ถูกเรียกถ้าวิธีการข้างต้นส่งกลับศูนย์แม้ว่าฉันทำซ้ำการทดสอบข้างต้นเพียงเพื่อความสมบูรณ์



0

ฉันเห็นด้วยกับคำตอบของไบรอัน

ถ้าฉันทำ

cell.isUserInteractionEnabled = false 

จากนั้นภาพรวมภายในเซลล์จะไม่ถูกโต้ตอบกับผู้ใช้

บนไซต์อื่นการตั้งค่า

cell.selectionStyle = .none

จะเรียกใช้วิธีการ didSelect แม้ว่าจะไม่ได้อัปเดตสีที่เลือก

การใช้ willSelectRowAt เป็นวิธีที่ฉันแก้ไขปัญหาของฉัน ตัวอย่าง:

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {

    if indexPath.section == 0{

        if indexPath.row == 0{
            return nil
        }

    }
    else if indexPath.section == 1{

        if indexPath.row == 0{
            return nil
        }

    }

    return indexPath

}

0

appart จากtableView.allowsMultipleSelection = trueคุณจะต้องยกเลิกการเลือกส่วนที่เหลือของเซลล์เมื่อเลือก:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if indexPath.section does not support multiple selection {
        // deselect the rest of cells
        tableView
            .indexPathsForSelectedRows?.compactMap { $0 }
            .filter { $0.section == indexPath.section && $0.row != indexPath.row }
            .forEach { tableView.deselectRow(at: $0, animated: true) }
    }
}

-1

สำหรับ swift 3.0 คุณสามารถใช้รหัสด้านล่างเพื่อปิดใช้งานการโต้ตอบกับผู้ใช้ไปยังเซลล์ UITableView

 cell.isUserInteractionEnabled = false
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.