Il semble que aspect fit
aligne l'image sur le bas du cadre par défaut. Existe-t-il un moyen de remplacer l’alignement tout en conservant aspect fit
intact?
** MODIFIER **
Cette question est antérieure à la mise en page automatique. En fait, la mise en page automatique a été révélée dans WWDC 2012 la même semaine que cette question avait été posée
En bref, vous ne pouvez pas faire cela avec une UIImageView
.
Une solution consiste à sous-classer une UIView
contenant une UIImageView
et à changer son cadre en fonction de la taille de l'image. Par exemple, vous pouvez trouver une version ici .
Pour ce faire, vous devez modifier la propriété contentsRect de la couche UIImageView. Le code suivant de mon projet (sous-classe de UIImageView) suppose scaleToFill et décale l'image de telle sorte qu'elle aligne le haut, le bas, la gauche ou la droite au lieu de l'alignement central par défaut. Pour AspectFit, ce serait une solution similaire.
typedef NS_OPTIONS(NSUInteger, AHTImageAlignmentMode) {
AHTImageAlignmentModeCenter = 0,
AHTImageAlignmentModeLeft = 1 << 0,
AHTImageAlignmentModeRight = 1 << 1,
AHTImageAlignmentModeTop = 1 << 2,
AHTImageAlignmentModeBottom = 1 << 3,
AHTImageAlignmentModeDefault = AHTImageAlignmentModeCenter,
};
- (void)updateImageViewContentsRect {
CGRect imageViewContentsRect = CGRectMake(0, 0, 1, 1);
if (self.image.size.height > 0 && self.bounds.size.height > 0) {
CGRect imageViewBounds = self.bounds;
CGSize imageSize = self.image.size;
CGFloat imageViewFactor = imageViewBounds.size.width / imageViewBounds.size.height;
CGFloat imageFactor = imageSize.width / imageSize.height;
if (imageFactor > imageViewFactor) {
//Image is wider than the view, so height will match
CGFloat scaledImageWidth = imageViewBounds.size.height * imageFactor;
CGFloat xOffset = 0.0;
if (BM_CONTAINS_BIT(self.alignmentMode, AHTImageAlignmentModeLeft)) {
xOffset = -(scaledImageWidth - imageViewBounds.size.width) / 2;
} else if (BM_CONTAINS_BIT(self.alignmentMode, AHTImageAlignmentModeRight)) {
xOffset = (scaledImageWidth - imageViewBounds.size.width) / 2;
}
imageViewContentsRect.Origin.x = (xOffset / scaledImageWidth);
} else if (imageFactor < imageViewFactor) {
CGFloat scaledImageHeight = imageViewBounds.size.width / imageFactor;
CGFloat yOffset = 0.0;
if (BM_CONTAINS_BIT(self.alignmentMode, AHTImageAlignmentModeTop)) {
yOffset = -(scaledImageHeight - imageViewBounds.size.height) / 2;
} else if (BM_CONTAINS_BIT(self.alignmentMode, AHTImageAlignmentModeBottom)) {
yOffset = (scaledImageHeight - imageViewBounds.size.height) / 2;
}
imageViewContentsRect.Origin.y = (yOffset / scaledImageHeight);
}
}
self.layer.contentsRect = imageViewContentsRect;
}
class AlignmentImageView: UIImageView {
enum HorizontalAlignment {
case left, center, right
}
enum VerticalAlignment {
case top, center, bottom
}
// MARK: Properties
var horizontalAlignment: HorizontalAlignment = .center
var verticalAlignment: VerticalAlignment = .center
// MARK: Overrides
override var image: UIImage? {
didSet {
updateContentsRect()
}
}
override func layoutSubviews() {
super.layoutSubviews()
updateContentsRect()
}
// MARK: Content layout
private func updateContentsRect() {
var contentsRect = CGRect(Origin: .zero, size: CGSize(width: 1, height: 1))
guard let imageSize = image?.size else {
layer.contentsRect = contentsRect
return
}
let viewBounds = bounds
let imageViewFactor = viewBounds.size.width / viewBounds.size.height
let imageFactor = imageSize.width / imageSize.height
if imageFactor > imageViewFactor {
// Image is wider than the view, so height will match
let scaledImageWidth = viewBounds.size.height * imageFactor
var xOffset: CGFloat = 0.0
if case .left = horizontalAlignment {
xOffset = -(scaledImageWidth - viewBounds.size.width) / 2
}
else if case .right = horizontalAlignment {
xOffset = (scaledImageWidth - viewBounds.size.width) / 2
}
contentsRect.Origin.x = xOffset / scaledImageWidth
}
else {
let scaledImageHeight = viewBounds.size.width / imageFactor
var yOffset: CGFloat = 0.0
if case .top = verticalAlignment {
yOffset = -(scaledImageHeight - viewBounds.size.height) / 2
}
else if case .bottom = verticalAlignment {
yOffset = (scaledImageHeight - viewBounds.size.height) / 2
}
contentsRect.Origin.y = yOffset / scaledImageHeight
}
layer.contentsRect = contentsRect
}
}
Il suffit de définir la priorité de la contrainte de présentation inférieure d’imageView sur la valeur la plus faible (c’est-à-dire 250) et le travail s’effectuera.
J'avais un problème similaire ... La manière la plus simple était de créer sa propre sous-classe de UIImageView. J'ajoute pour les propriétés de la sous-classe 3, de sorte qu'il peut maintenant être utilisé facilement sans connaître l'implémentation interne:
@property (nonatomic) LDImageVerticalAlignment imageVerticalAlignment;
@property (nonatomic) LDImageHorizontalAlignment imageHorizontalAlignment;
@property (nonatomic) LDImageContentMode imageContentMode;
Vous pouvez vérifier ici: https://github.com/LucasssD/LDAlignmentImageView
J'ai résolu ce problème de manière native dans Interface Builder en définissant une contrainte sur la hauteur de UIImageView, car l'image serait toujours «relevée» lorsque l'image était plus grande que la taille de l'écran.
Plus spécifiquement, j'ai défini UIImageView sur la même hauteur que la vue dans laquelle il se trouve (via la contrainte de hauteur), puis je l'ai positionné avec des contraintes d'espacement dans IB. Il en résulte que le UIImageView a un 'Aspect Fit' qui respecte toujours la contrainte d'espacement supérieure que j'ai définie dans IB.