web-dev-qa-db-fra.com

UIImage aspect ajustement et aligner

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

34
Jacksonkr

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

22
Mundi

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;
}

Version rapide

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
    }

}
5
Werner Altewischer

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.

4
protspace

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

1
Łukasz Duda

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.

0
David T
  1. Ajoutez la contrainte de format d'image avec les proportions de votre image.
  2. Ne pas épingler UIImageView en bas.
  3. Si vous souhaitez modifier le UIImage de manière dynamique, n'oubliez pas de mettre à jour la contrainte de format d'image.
0