2016-04-29 9 views
2

私は1ピクセルのダッシュラインを描画しようとしていますが、常に2ピクセルのラインを描画します。現在のソリューション:CAShapeLayer 1pxダッシュライン

let shapelayer = CAShapeLayer() 
let path = UIBezierPath() 
path.moveToPoint(CGPoint(x: x, y: y)) 
path.addLineToPoint(CGPoint(x: x, y: y)) 

shapelayer.strokeColor = UIColor.whiteColor().CGColor 
shapelayer.lineWidth = 1.0/UIScreen.mainScreen().scale 
shapelayer.lineJoin = kCALineJoinMiter 
shapelayer.lineDashPattern = [1, 3] 
shapelayer.path = path.CGPath 
layer.addSublayer(shapelier) 
+0

ストロークがラインをサドルするので、直線のピクセル行の中心線上にあることを常に確認する必要があります。おそらく、1xまたは3xディスプレイの場合は0.5ポイント、2xディスプレイの場合は0.25ポイントでオフセットする必要があります。また、「contentsScale」を設定することは、マットが指摘するように良い考えです;) – Hamish

+0

ピクセルをポイントと混同しないでください。あなたは1つの_point_行を要求しており、あなたはそれを取得しています。あなたが得ているのは、2ピクセルレンダリングです。 – matt

答えて

3

シェイプレイヤーを使用すると、二重解像度の画面を持って知っていないので、それは1ポイントラインを描いていると、それが画面上に2つのピクセルに倍増されているためです。シェイプレイヤのcontentsScaleを画面の表示スケールに設定する必要があります。

この問題は、自分で作成したレイヤー(このようなもの)に対してのみ発生します。

+0

残っているコードがまだ残っているからです。あなたの '/ UIScreen.mainScreen()。scale'を取り除きます。赤ちゃんです。正確にスケーリングされたレイヤーに1ポイントの線を描画すれば、すべてがうまくいくでしょう。 – matt

+0

私が間違っていると私を訂正しますが、 'contentsScale'は、デバイスがレンダリングする"論理 "ピクセルのバッキングストアのサイズにのみ影響します - それは、必要に応じてアップサンプリングまたはダウンサンプリングされ、物理的な表示?したがって、1xコンテンツのスケーリングされたバッキングストアに描画された1ptの線は、2xディスプレイに描画されるように2倍アップサンプリングされ、2pxの線になります。同様に、2倍のバッキングストアに描画され、次に2倍のディスプレイにまっすぐに表示される1ptの線はサンプリングされず、2pxの線も同様にサンプリングされます。 – Hamish

+0

したがって、 'contentsScale'は実際に表示される行の幅に影響を与えるべきではありません。私は、OPが持っている問題は、1pxの線幅で1行の線の長さを持つ1つの線のダッシュセグメントを描こうとしていることです。したがって、画面上の各ダッシュに対して2x1ピクセルのセグメントが生成されます。あなたのソリューションは、1x1 pt線分を生成します。これは、2xディスプレイで2x2pxになります。 – Hamish

1

@matt is correctあなたのレイヤのcontentsScaleを変更することについて - これはあなたがここで直面している問題ではないようです。

レイヤのcontentsScaleは、レイヤがレンダリングされる「論理」ピクセルのバッキングストアのサイズにのみ影響します。しかし、物理的なスクリーン上に表示されるために、このバッキングストアは、実際のデバイスの物理座標系と一致するように、ダウンサンプリングまたはアップサンプリングされる。

「論理」ピクセルの1倍コンテンツスケーリングされたバッキングストアに1ptの線を描画すると、その座標系の1px線として表されます。ただし、2xディスプレイに表示するにはアップサンプリングする必要があります。これは効果的に2倍の幅になります(ただし、アップサンプリングの性質は品質が低下することを意味します)。

倍精度浮動小数点型ストアで1ptの線を描画すると、その座標系で2px線として表されます。バッキング座標系&の物理座標系が一致するので、サンプリングする必要はなく、2xディスプレイに2px線として表示されます。

したがって、contentsScaleは、実際には、フィジカルのピクセル比率には影響しません。品質にのみ影響します(サンプリングのため)。したがって、サンプリングによる品質の低下を避けるために、デバイスのディスプレイの物理的なスケールと "論理"ピクセルのバッキング表示のスケールを一致させる必要があるため、contentsScaleの画面のスケールを使用する必要があります。ただし、線幅に1.0を使用すると、線幅がポイントで定義されているので、contentsScaleにかかわらず、2xディスプレイでは2px線、3xディスプレイでは3px線が生成されます。線幅をピクセル単位で測定したい場合は、画面の縮尺で分割する必要があります。


あなたの疑問を持っているように見える問題は、あなたが1ピクセルの線幅と線を引くしているということです、しかしあなたは(ダッシュパターンの線長さため1PTを設定しています)。したがって、2xのディスプレイでは、各セグメントが2x1ピクセルを占めるラインにつながります。

解決策は、のラインダッシュパターンと同様に、lineWidthを指定することです。たとえば:

shapelayer.lineDashPattern = [1.0/UIScreen.mainScreen().scale, 3] // set whatever you want for the unstroked line dash length 
shapelayer.lineWidth = 1.0/UIScreen.mainScreen().scale 

さらに、あなたがクリップしたいピクセルに応じて、2倍のディスプレイ上の1倍または3倍の表示、および0.25ポイント(0.75ポイントで0.5ポイント、あなたのパスをオフセットする必要がありますとの行)。このオフセットは、水平の場合はラインのy座標に、垂直の場合はx座標に適用するとよいでしょう。これは、ラインのストロークがラインに「鞍を打つ」ことを意味します。つまり、ラインの両側に描画されます。ラインの位置に整数を使用すると、ピクセル境界上にそれを描画します。

通常、ポイントを使用するときに大きな影響はありませんが、ピクセルレベルで描画する場合は重要です。ラインをオフセットするとピクセルの中心に揃えられます。つまり、ストロークは1ピクセルだけを占めます。 1ピクセルのラインがピクセル中心に正しく配置されていないと、2ピクセルに渡って輝度が低下して表示され、望ましくない効果が生じます。

関連する問題