2016-04-07 45 views
1

Metni, dairesel veya oval şekilli bir bölgenin ortasında oluşturmaya çalışıyorum. İdeal olarak, metni dikey ve yatay olarak ortalamak istiyorum, ancak bölgenin sınırları içinde doğal olarak akmasını sağladım.Düzensiz şekilli bir metinde dikey olarak ortalanmış metin UITextView

UITextView ve NSTextContainer kullanarak, yatay olarak ortalanmış (dikey olarak) belirli bir dikey ofsette metni yerleştirme işlemini iyi yapan bir dışlama yolları kullanarak bir yaklaşım buldum. Ancak, dikey merkezleme nasıl elde edileceğinden emin değilim.

Tüm gördüğüm yaklaşımlar, metin yerleştirildikten ve son yükseklik bilindikten sonra metin görünümünün contentInset ayarlanmasını önerir. (Örneğin, this question) Ancak, düzensiz şekilli bir bölge durumunda, yerleştirildikten sonraki metnin yüksekliği, bölge yerleşiminin neresinden başladığına bağlı olacaktır.

Değerlendirdiğim bir yaklaşım, tatmin edici bir düzen elde edilene kadar düzen işlemini yeniden denemektir. Bu tarz bir yaklaşımla herkes başarılı oldu mu? Buradaki bir zorluk, tüm metnin görüntü içinde oluşturulup oluşturulmadığını (yani, tüm metni yerleştirmek için yeterli alan olup olmadığını) nasıl belirleyeceğimi değil, tüm içeriğin olup olmadığını sorgulamanın bir yolunu bulmamdır. bir UITextView kullanırken 'render edildi'?

Son olarak: bu yalnızca metin görüntülemek içindir --- kullanıcının görünümün içeriğini düzenlemesine izin verilmesine gerek yoktur. CoreText, bu durumda daha iyi bir yaklaşım olabilir mi?

iOS geliştirmede oldukça yeniyim, bu yüzden yaptığım çok kötü bir şey varsa, bunu bilmek de yararlı olacaktır!

Teşekkürler!

let boundingRect = CGRect(...) 
let textView = UITextView(frame: boundingRect) 

textView.editable = false 
view.addSubview(textView) 

let verticalInset:CGFloat = <some value> 

let width = boundingRect.width 
let height = boundingRect.height 
let textBounds = CGSize(width: width, height:height - 2*verticalInset) 
textView.bounds = textBounds 

let exclusionRect = CGRect(x:0, y:-verticalInset, width:width, height:height) 

let textRegion = UIBezierPath(ovalInRect: exclusionRect)  
let exclusionPath = UIBezierPath(rect:exclusionRect) 
exclusionPath.appendPath(textRegion.bezierPathByReversingPath()) 

textView.textContainer.exclusionPaths = [exclusionPath] 

let paragraphStyle = NSMutableParagraphStyle() 
paragraphStyle.alignment = .Center 

let attributes = [NSParagraphStyleAttributeName: paragraphStyle] 
let formattedContent = NSAttributedString(string: "....", attributes:attributes) 

textView.attributedText(formattedContent) 

İşte görselleştirmek yardımcı olmak için bir görüntü var yardımcı olursa, yukarıdaki: example

+0

Tam olarak şu anda çalışmaya çalıştığım şey budur! TextKit'in gitmenin tek yolu olabileceğini düşünüyorum. –

cevap

0

Burada bir harika cevap sunamaz. Bununla birlikte, YYText'u denedim. Bu, dikey metin hizalamayı ve hariç tutma yollarını destekleyen bir "YYLabel" değerine sahiptir. Demo projelerine, özellikle de 'TextAttributes1' satırına kendi tablo görünümlerinde bir göz atın.

+0

@Christopher önerisi için çok teşekkürler. Bunu kontrol edeceğim. Aslında --- ben de benim için bir uygulanabilir çözüm bulmak için başardı - güzel değil, ama şimdi için iyi - hangi yazacağım aşağıda. Şerefe! – duncanm

+0

Oop - eklemeniz gerekenler: Bir kez YYText'i kontrol etme şansım oldu, cevabınızı işaretleyecektir. – duncanm

1

Dikdörtgen bir alanda metin yerleştirirseniz, yukarı veya aşağı doğru kaydırarak dikey olarak ortalamak kolaydır. Alan dikdörtgensel değilse, sizin durumunuzda olduğu gibi, bu mümkün değildir, çünkü metin dikey olarak kaydırdıktan sonra şekle sığmaz.

Buna bir çözümün her zaman yinelenen bir yöntem olduğuna inanıyorum. Örneğin: Metni, artan insets ile şekillendirin ve metnin ortaya çıkan şekle sığması için en geniş girişi bulun.Bütün dize hale getirilmesi durumunda kontrol edebilirsiniz, bu frame ile

let text:NSAttributedString = ... // The text to render 
let path:CGPath = ... // Bounds the shape in which the text is rendered 
let framesetter = CTFramesetterCreateWithAttributedString(text) 
let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, nil) 

:

Çekirdek Metin ile Bunu yapmak için, böyle bir metin düzeni için bir CTFrame oluşturabilir

let range = CTFrameGetVisibleStringRange(frame) 
if text.length == range.length { 
    // Fits 
} 

Ve metin oluşturmak için:

let ctx:CGContext = ... 
CTFrameDraw(renderFrame, ctx) 

Eğer İşlenen metin hakkında daha fazla ayrıntıya ihtiyacınız varsa, frame'dan CTLine s değerini almak için CTFrameGetLines'u kullanabilirsiniz. Ardından, UseGlyphPathBounds veya UseOpticalBounds seçenekleriyle CTFrameGetLineOrigins ve CTLineGetBoundsWithOptions kullanarak, tek satırların optik sınırlarını hesaplayabilirsiniz. Bu daha hassas bir dikey ayarlamaya izin verir. (CoreText'i CoreGraphics ile kullanmak için ihtiyaç duyulan koordinat sistemi dönüşümleri, biraz lineer cebir için kendinizi güçlendirin, biraz can sıkıcı olabilir).