Collection View Programming Guide によれば、UICollectionViewDelegate
のセルのハイライトの視覚状態を処理する必要があります。このような:
- (void)collectionView:(PSUICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
MYCollectionViewCell *cell = (MYCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
[cell highlight];
}
- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
MYCollectionViewCell *cell = (MYCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
[cell unhighlight];
}
私がこのアプローチについて気に入らないのは、セルに非常に固有のロジックをデリゲートに追加することです。実際、UICollectionViewCell
は、highlighted
プロパティを介して、強調表示された状態を個別に管理します。
setHighlighted:
をオーバーライドすることは、よりクリーンなソリューションになりませんか?
- (void)setHighlighted:(BOOL)highlighted
{
[super setHighlighted:highlighted];
if (highlighted) {
[self highlight];
} else {
[self unhighlight];
}
}
デリゲートアプローチの代わりにこのアプローチに欠点はありますか?
ドキュメントにあるように、セルが強調表示されている間にhighlighted
プロパティを変更することに依存できます。たとえば、次のコードは、強調表示されたときにセルを赤にします(ただし、サブビューではありません)。
- (void)setHighlighted:(BOOL)highlighted {
[super setHighlighted:highlighted];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
if (self.highlighted) {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 1, 0, 0, 1);
CGContextFillRect(context, self.bounds);
}
}
そしてaddのような場合、背景は紫色(赤+不透明な青)になります:
- (void)collectionView:(UICollectionView *)colView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [colView cellForItemAtIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.5];
}
- (void)collectionView:(UICollectionView *)colView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [colView cellForItemAtIndexPath:indexPath];
cell.contentView.backgroundColor = nil;
}
したがって、両方を一緒に使用できます(必ずしも両方がセルの外観を変更するわけではありません)。違いは、デリゲートメソッドではindexPath
も持つことです。複数選択の作成(このメソッドを選択デリゲートメソッドと併用)、セルの強調表示中のプレビューの表示、他のビューでのアニメーションの表示などに使用できます...このデリゲートにはかなりの数のアプライアンスがあります私の意見では方法。
結論として、セルの外観はセル自体が処理するようにし、デリゲートメソッドを使用して、コントローラーが同時にクールなものを作成できるようにします。
2つの可能なアプローチの概要を以下に示します。
セルのサブクラス化
既にUICollectionViewCell
からサブクラス化されている場合、よりクリーンなアプローチ。
class CollectionViewCell: UICollectionViewCell {
override var highlighted: Bool {
didSet {
self.contentView.backgroundColor = highlighted ? UIColor(white: 217.0/255.0, alpha: 1.0) : nil
}
}
}
ICollectionViewDelegate
クリーン度が低いため、コレクションビューのデリゲートがセルの表示ロジックを知る必要があります。
func collectionView(collectionView: UICollectionView, didHighlightItemAtIndexPath indexPath: NSIndexPath) {
if let cell = collectionView.cellForItemAtIndexPath(indexPath) {
cell.contentView.backgroundColor = UIColor(white: 217.0/255.0, alpha: 1.0) // Apple default cell highlight color
}
}
func collectionView(collectionView: UICollectionView, didUnhighlightItemAtIndexPath indexPath: NSIndexPath) {
if let cell = collectionView.cellForItemAtIndexPath(indexPath) {
cell.contentView.backgroundColor = nil
}
}
UICollectionViewCell
にはselectedBackgroundView
プロパティがあることに注意してください。デフォルトでは、nilです。このプロパティのビューを作成するだけで、ユーザーがセルに触れると表示されます。
override func awakeFromNib() {
super.awakeFromNib()
let view = UIView(frame: contentView.bounds)
view.isUserInteractionEnabled = false
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.backgroundColor = UIColor(white: 0.94, alpha: 1.0)
selectedBackgroundView = view
}
まあ...これらの方法はすべて正しいからです。私にとって最も簡単な方法を見つけました。 setSelected:メソッドをオーバーライドするだけです(たとえば、背景色を変更するため)。
-(void)setSelected:(BOOL)selected{
self.backgroundColor = selected?[UIColor greenColor]:[UIColor grayColor];
[super setSelected:selected];
}
...「そのままで」動作する(collectionView.allowsMultipleSelectionでも)
セルを強調表示するには十分です(Swift 4)
class MyCollectionViewCell: UICollectionViewCell {
...
override var isHighlighted: Bool {
didSet {
if isHighlighted {
self.contentView.alpha = 0.6
}
else {
self.contentView.alpha = 1.0
}
}
}
}
UICollectionViewCell.hから直接取得-setSelected
とsetHighlighted
の両方をオーバーライドするのが正しい。状況に応じて、選択時に自動的に交換されるbackgroundView
とselectedBackgroundView
にカスタムビューを割り当てることを検討できます。
// Cells become highlighted when the user touches them.
// The selected state is toggled when the user lifts up from a highlighted cell.
// Override these methods to provide custom UI for a selected or highlighted state.
// The collection view may call the setters inside an animation block.
@property (nonatomic, getter=isSelected) BOOL selected;
@property (nonatomic, getter=isHighlighted) BOOL highlighted;
// The background view is a subview behind all other views.
// If selectedBackgroundView is different than backgroundView, it will be placed above the background view and animated in on selection.
@property (nonatomic, retain) UIView *backgroundView;
@property (nonatomic, retain) UIView *selectedBackgroundView;
Swift 3:(A-Liveの回答に基づく)
import UIKit
class MyCollectionViewCell: UICollectionViewCell {
override var highlighted: Bool {
didSet {
self.setNeedsDisplay()
}
}
override func drawRect(rect: CGRect) {
super.drawRect(rect)
myImageView.highlighted = self.highlighted
}
}
スイフト4
import UIKit
class MyCollectionViewCell: UICollectionViewCell {
override var isHighlighted: Bool {
didSet {
self.setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
super.draw(rect)
myImageView.isHighlighted = self.isHighlighted
}
}