ios - tutorial - uicollectionviewcontroller
UICollectionView Seleccionar y anular la selección del problema (13)
Así que tengo un objeto principal que tiene muchas imágenes asociadas a él. Una imagen también es un objeto.
Digamos que tienes un controlador de vista de colección, y en ese controlador tienes
cellForItemAtIndexPath
bien basado en el objeto principal, si tiene la imagen actual asociada con él, quiero establecer seleccionado en verdadero. Pero quiero que el usuario pueda "deseleccionar" esa celda actual en cualquier momento para eliminar su asociación con el objeto principal.
Me parece que si establece "seleccionado en verdadero", si hay una relación entre el objeto principal y la imagen en cellForItemAtIndexPath
, la des-selección ya no es una opción.
en
didDeselectItemAtIndexPath
y
didSelectItemAtIndexPath
Pruebo con un registro para ver si se llaman. Si una celda está configurada para seleccionar - se llama a cellForItemAtIndexPath
, pero si nunca configuro una celda para seleccionar en cellForItemAtIndexPath
, puedo seleccionar y deseleccionar todo lo que quiero.
¿Es esta la manera intencional en que se supone que funciona una vista de colección? Leo los documentos y no parece hablar de que sea así. Interpreto que los documentos significan que funciona de la forma en que lo haría una celda de vista de tabla. con algunos cambios obvios
Esto también muestra que el controlador está configurado correctamente y está utilizando los métodos de delegado apropiados ... hmmmm
¿Has mirado a:
- (BOOL)collectionView:(PSTCollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath;
Por favor, indique su problema más claramente y quizás podamos llegar al fondo del problema. Acabo de pasar un tiempo con UICollectionView.
Creo que su problema puede deberse a la confusión de que si establece cell.selected = YES
programmatically, el motivo didSelectItemAtIndexPath:
no se llama es porque solo se utiliza cuando la colecciónView es responsable de la selección de la celda (por ejemplo, a través de un grifo).
¿Tienes un método setSelected
personalizado en tu clase Cell? ¿Estás llamando [super setSelected:selected]
en ese método?
Tenía un problema misterioso en el que usaba selección múltiple, no pude anular la selección de las celdas una vez que fueron seleccionadas. Llamar al supermétodo solucionó el problema.
Al llamar tanto [UICollectionViewCell setSelected:]
como [UICollectionView selectItemAtIndexPath:animated:scrollPosition:]
en [UICollectionView collectionView:cellForItemAtIndexPath:]
no funciona, intente llamarlos dentro de un dispatch_async(dispatch_get_main_queue(), ^{});
bloquear.
Eso es lo que finalmente lo resolvió para mí.
Aquí está mi respuesta para Swift 2.0.
Pude configurar lo siguiente en viewDidLoad ()
collectionView.allowsMultipleSelection = true;
luego implementé estos métodos
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! MyCell
cell.toggleSelected()
}
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! MyCell
cell.toggleSelected()
}
finalmente
class MyCell : UICollectionViewCell {
....
func toggleSelected ()
{
if (selected){
backgroundColor = UIColor.orangeColor()
}else {
backgroundColor = UIColor.whiteColor()
}
}
}
Esto es un poco viejo, pero dado que encuentro el mismo problema usando swift, agregaré mi respuesta. Cuando usas:
collectionView.selectItemAtIndexPath(indexPath, animated: true, scrollPosition: [])
La celda no fue seleccionada en absoluto. Pero al usar:
cell.selected = true
Se seleccionó pero no pude seleccionar / deseleccionar la celda nunca más.
Mi solución (use ambos métodos):
cell.selected = true
collectionView.selectItemAtIndexPath(indexPath, animated: true, scrollPosition: .None)
Cuando se invocan estos dos métodos:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
¡Funcionó perfectamente!
Estoy usando una subclase de celda personalizada, para mí solo tuve que establecer self.selected = false
en prepareForReuse()
en la subclase.
La selección y deselección de celda se maneja mejor configurando una vista de fondo y una vista de fondo seleccionada. Recomiendo asegurarse de que los dos marcos de estas vistas estén establecidos correctamente en el método layoutSubviews (si configura la vista seleccionada y de fondo mediante IB).
No olvide configurar el color de fondo de su contentView (si tiene uno) para borrar para que se muestre la vista de fondo correcta.
Nunca establezca la selección de la celda directamente (es decir, a través de cell.selected = YES), use los métodos diseñados para este propósito en la vista de colección. Está claramente explicado en los documentos, aunque estoy de acuerdo en que la información está algo fragmentada en las guías.
No debería necesitar meter los colores de fondo de una celda directamente en su origen de datos collectionView.
Además, como nota final, no te olvides de llamar a [superpreparado para Reutilizar] y [superconfigurado: seleccionado] si estás implementando estos en la clase de tu celda, ya que puedes evitar que la superclase de la celda haga la selección de celda.
Dame me gusta si necesitas más aclaraciones sobre este tema.
No sé por qué UICollectionView
es tan desordenado como este en comparación con UITableViewController
... Unas cuantas cosas que descubrí.
La razón por la que setSelected:
se llama varias veces se debe a que se llaman los métodos de secuencia. La secuencia es muy similar a la de los métodos UITextFieldDelegate
.
El método collectionView:shouldSelectItemAtIndexPath:
se llama antes de que collectionView
realmente seleccione la celda porque en realidad está preguntando "¿Debería ser seleccionado?"
collectionView:didSelectItemAtIndexPath:
se llama de hecho después de que collectionView
selecciona la celda. De ahí el nombre "seleccionó".
Entonces esto es lo que está sucediendo en su caso (y mi caso, y tuve que luchar horas sobre esto).
El usuario vuelve a tocar una celda seleccionada para anular la selección. shouldSelectItemAtIndexPath:
se llama para verificar si se debe seleccionar la celda. El collectionView
selecciona la celda y se llama a didSelectItemAtIndexPath
. Cualquier cosa que haga en este punto es después de que la propiedad selected
la celda esté establecida en YES
. Es por eso que algo como cell.selected = !cell.selected
no funcionará.
TL; DR - Haga que su collectionView
anule la selección de la celda en el método de delegado collectionView:shouldSelectItemAtIndexPath:
invocando deselectItemAtIndexPath:animated:
y devuelva NO
.
Breve ejemplo de lo que hice:
- (BOOL)collectionView:(OPTXListView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSArray *selectedItemIndexPaths = [collectionView indexPathsForSelectedItems];
if ([selectedItemIndexPaths count]) {
NSIndexPath *selectedIndexPath = selectedItemIndexPaths[0];
if ([selectedIndexPath isEqual:indexPath]) {
[collectionView deselectItemAtIndexPath:indexPath animated:YES];
return NO;
} else {
[collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
return YES;
}
} else {
[collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
return YES;
}
}
No sé si entiendo el problema, pero el estado seleccionado se establece por celda e incluiría todas las subvistas dentro de la celda. No explicas lo que quieres decir con "un objeto principal tiene muchas imágenes asociadas con él". Asociado como en las subvistas? ¿O qué tipo de asociación exactamente quieres decir?
Me parece un problema de diseño. Quizás necesites una subclase UIView que contenga los objetos asociados que necesites; esa subclase se puede establecer como la vista de contenido. Hago esto, por ejemplo, donde tengo una imagen, una descripción y una grabación de sonido relacionada con la imagen. Todos se definen en la subclase y luego cada una de estas subclases se convierte en una vista de contenido para una sola celda.
También usé un arreglo para imágenes relacionadas a una carpeta que las contiene. Bajo esta configuración, las carpetas y las imágenes tienen una subclase y cualquiera de ellas se puede adjuntar a una celda como una vista de contenido (estas se almacenan en los datos centrales como una sola entidad).
¿Quizás puedas explicar tu problema?
Tuve el mismo problema, es decir. configuración cell.selected = YES
en [UICollectionView collectionView:cellForItemAtIndexPath:]
luego no se puede anular la selección de la celda tocando sobre ella.
Solución por ahora: llamo a ambos [UICollectionViewCell setSelected:]
y [UICollectionView selectItemAtIndexPath:animated:scrollPosition:]
en [UICollectionView collectionView:cellForItemAtIndexPath:]
.
Tuve un problema de UICollectionView
selección con UICollectionView
y descubrí que no permitía la selección múltiple en collectionView. Entonces, cuando estaba probando, siempre intenté en la misma celda y si la selección individual está activada, no se puede anular la selección de una celda ya seleccionada.
Tuve que agregar:
myCollectionView.allowsMultipleSelection = YES;
Viviendo en la era de iOS 9, hay varias cosas para verificar aquí.
- Compruebe si tiene
collectionView.allowsSelection
establecido enYES
- Compruebe si tiene
collectionView.allowsMultipleSelection
establecido enYES
(si necesita esa capacidad)
Ahora viene la parte fan. Si escuchas a Apple y configuras backgroundColor
en cell.contentView
lugar de cell
propia cell
, entonces has ocultado su selectedBackgroundView
para que nunca sea visible. Porque:
(lldb) po cell.selectedBackgroundView
<UIView: 0x7fd2dae26bb0; frame = (0 0; 64 49.5); autoresize = W+H; layer = <CALayer: 0x7fd2dae26d20>>
(lldb) po cell.contentView
<UIView: 0x7fd2dae22690; frame = (0 0; 64 49.5); gestureRecognizers = <NSArray: 0x7fd2dae26500>; layer = <CALayer: 0x7fd2dae1aca0>>
(lldb) pviews cell
<MyCell: 0x7fd2dae1aa70; baseClass = UICollectionViewCell; frame = (0 0; 64 49.5); clipsToBounds = YES; hidden = YES; opaque = NO; layer = <CALayer: 0x7fd2dae1ac80>>
| <UIView: 0x7fd2dae26bb0; frame = (0 0; 64 49.5); autoresize = W+H; layer = <CALayer: 0x7fd2dae26d20>>
| <UIView: 0x7fd2dae22690; frame = (0 0; 64 49.5); gestureRecognizers = <NSArray: 0x7fd2dae26500>; layer = <CALayer: 0x7fd2dae1aca0>>
| | <UIView: 0x7fd2dae24a60; frame = (0 0; 64 49.5); clipsToBounds = YES; alpha = 0; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x7fd2dae1acc0>>
| | <UILabel: 0x7fd2dae24bd0; frame = (0 0; 64 17.5); text = ''1''; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fd2dae240c0>>
| | <UILabel: 0x7fd2dae25030; frame = (0 21.5; 64 24); text = ''1,04''; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fd2dae25240>>
(lldb) po cell.contentView.backgroundColor
UIDeviceRGBColorSpace 0.4 0.4 0.4 1
Por lo tanto, si desea utilizar selectedBackgroundView (que es el que se activa / desactiva con cell.selected
y selectItemAtIndexPath...
), haga lo siguiente:
cell.backgroundColor = SOME_COLOR;
cell.contentView.backgroundColor = [UIColor clearColor];
y debería funcionar bien.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath)
if cell?.selected == true{
cell?.layer.borderWidth = 4.0
cell?.layer.borderColor = UIColor.greenColor().CGColor
}
}func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath)
if cell?.selected == false{
cell?.layer.borderColor = UIColor.clearColor().CGColor
}
}
Solución simple que encontré