Beispiel #1
0
        protected override Size MeasureOverride(Size size)
        {
            var hasSameDesiredSize =
                !_measureInvalidated &&
                _previousAvailableSize != null &&
                _previousDesiredSize.Width == size.Width &&
                _previousDesiredSize.Height == size.Height;

            var isSingleLineNarrower =
                !_measureInvalidated &&
                _previousAvailableSize != null &&
                _previousDesiredSize.Width <= size.Width &&
                _previousDesiredSize.Height == size.Height;

            if (hasSameDesiredSize || isSingleLineNarrower)
            {
                return(_previousDesiredSize);
            }
            else
            {
                _previousAvailableSize = size;
                _measureInvalidated    = false;

                UpdateTypography();

                var horizontalPadding = Padding.Left + Padding.Right;
                var verticalPadding   = Padding.Top + Padding.Bottom;

                // available size considering padding
                size.Width  -= horizontalPadding;
                size.Height -= verticalPadding;

                var result = LayoutTypography(size);

                if (result.Height == 0)                 // this can happen when Text is null or empty
                {
                    // This measures the height correctly, even if the Text is null or empty
                    // This matches Windows where empty TextBlocks still have a height (especially useful when measuring ListView items with no DataContext)
                    var font = NSFontHelper.TryGetFont((float)FontSize * 2, FontWeight, FontStyle, FontFamily);

                    var str = new NSAttributedString(Text, font);

                    var rect = str.BoundingRectWithSize(size, NSStringDrawingOptions.UsesDeviceMetrics);
                    result = new Size(rect.Width, rect.Height);
                }

                result.Width  += horizontalPadding;
                result.Height += verticalPadding;

                return(_previousDesiredSize = new CGSize(Math.Ceiling(result.Width), Math.Ceiling(result.Height)));
            }
        }
Beispiel #2
0
        protected override Size MeasureOverride(Size size)
        {
            // `size` is used to compare with the previous one `_previousDesiredSize`
            // We need to apply `Math.Ceiling` to compare them correctly
            var isSameOrNarrower =
                !_measureInvalidated &&
                _previousAvailableSize != null &&
                _previousDesiredSize.Width <= Math.Ceiling(size.Width) &&
                _previousDesiredSize.Height == Math.Ceiling(size.Height);

            if (isSameOrNarrower)
            {
                return(_previousDesiredSize);
            }
            else
            {
                _previousAvailableSize = size;
                _measureInvalidated    = false;

                UpdateTypography();

                var padding = Padding;

                // available size considering padding
                size = size.Subtract(padding);

                var result = LayoutTypography(size);

                if (result.Height == 0)                 // this can happen when Text is null or empty
                {
                    // This measures the height correctly, even if the Text is null or empty
                    // This matches Windows where empty TextBlocks still have a height (especially useful when measuring ListView items with no DataContext)
                    var font = NSFontHelper.TryGetFont((float)FontSize * 2, FontWeight, FontStyle, FontFamily);

                    using var str = new NSAttributedString(Text, font);

                    var rect = str.BoundingRectWithSize(size, NSStringDrawingOptions.UsesDeviceMetrics);
                    result = new Size(rect.Width, rect.Height);
                }

                result = result.Add(padding);

                return(_previousDesiredSize = new Size(Math.Ceiling(result.Width), Math.Ceiling(result.Height)));
            }
        }
Beispiel #3
0
        private NSStringAttributes GetAttributes()
        {
            var attributes = new NSStringAttributes();

            var font = NSFontHelper.TryGetFont((float)FontSize, FontWeight, FontStyle, FontFamily);

            attributes.Font            = font;
            attributes.ForegroundColor = Brush.GetColorWithOpacity(Foreground, Colors.Transparent).Value;

            if (TextDecorations != TextDecorations.None)
            {
                attributes.UnderlineStyle = (int)((TextDecorations & TextDecorations.Underline) == TextDecorations.Underline
                                        ? NSUnderlineStyle.Single
                                        : NSUnderlineStyle.None);

                attributes.StrikethroughStyle = (int)((TextDecorations & TextDecorations.Strikethrough) == TextDecorations.Strikethrough
                                        ? NSUnderlineStyle.Single
                                        : NSUnderlineStyle.None);
            }

            var paragraphStyle = new NSMutableParagraphStyle()
            {
                MinimumLineHeight = (nfloat)LineHeight,
                Alignment         = TextAlignment.ToNativeTextAlignment(),
                LineBreakMode     = GetLineBreakMode(),
            };

            // For unknown reasons, the LineBreakMode must be set to WordWrap
            // when applied to a NSTextStorage for text to wrap.
            if (UseLayoutManager)
            {
                paragraphStyle.LineBreakMode = NSLineBreakMode.ByWordWrapping;
            }

            if (LineStackingStrategy != LineStackingStrategy.MaxHeight)
            {
                paragraphStyle.MaximumLineHeight = (nfloat)LineHeight;
            }
            attributes.ParagraphStyle = paragraphStyle;

            if (LineHeight != 0 && font != null)
            {
                // iOS puts text at the bottom of the line box, whereas Windows puts it at the top.
                // Empirically this offset gives similar positioning to Windows.
                // Note: Descender is typically a negative value.
                var verticalOffset = LineHeight - font.XHeight /* MACOS TODO XHeight ? */ + font.Descender;

                // Because we're trying to move the text up (toward the top of the line box),
                // we only set BaselineOffset to a positive value.
                // A negative value indicates that the the text is already bottom-aligned.
                attributes.BaselineOffset = Math.Max(0, (float)verticalOffset);
            }

            if (CharacterSpacing != 0)
            {
                //CharacterSpacing is in 1/1000 of an em, iOS KerningAdjustment is in points. 1 em = 12 points
                attributes.KerningAdjustment = (CharacterSpacing / 1000f) * 12;
            }

            return(attributes);
        }