2017-09-27 26 views
1

注意:是的,我知道在Android中有其他的做按鈕的方式,但這只是一個例子來證明我的問題(實際按鈕要複雜得多)。所以請不要回復提供其他解決方案的Android按鈕,我正在尋找一個解決方案與PaintCode ...PaintCode繪圖代碼Android使用的是像素而不是點/ DP

我一直在使用PaintCode在iOS中繪製自定義按鈕多年,它工作出色。我想爲android做同樣的事情,並且有以下問題:

  1. 在PaintCode中,我繪製了一個基本上是圓角矩形的半徑爲20個點的按鈕。
  2. 我畫了一個框架,然後使用彈簧設置正確的大小調整行爲(請參見截圖)。
  3. 結果是,無論按鈕的大小是什麼(=框架),角落將始終用20點很好地舍入。基本上是一個很好的可調整大小的按鈕。

這工作得非常好iOS上,但在Android上,半徑爲20個像素點,導致遠小半徑(現與高分辨率的設備)。

或者一般情況下,使用PaintCode生成的繪製方法繪製時,在PaintCode中繪製的所有圖形都很小。

它接縫生成的繪圖代碼沒有考慮設備的規模(就像它在iOS上那樣)。

enter image description here

看着https://www.paintcodeapp.com/documentation/android節「規模」 PaintCode建議與密度指標在android系統進行縮放播放。 這確實有效,但會使生成的圖形變得模糊,我想這是因爲我們正在縮放而導致圖像分辨率較低。所以它不是一個可行的解決方案。

class Button1 @JvmOverloads constructor(
     context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 
) : Button(context, attrs, defStyleAttr) { 

    var frame = RectF() 

    override fun onDraw(canvas: Canvas?) { 
     super.onDraw(canvas) 
     val displayDensity = resources.displayMetrics.density 
     canvas?.scale(displayDensity, displayDensity) 
     frame.set(0f,0f,width.toFloat()/displayDensity,height.toFloat()/displayDensity) 
     StyleKitName.drawButton1(canvas, frame) 
    } 
} 

任何建議來解決這個問題?這是PaintCode中的錯誤嗎?

回答

5

我是開發人員。很抱歉,很長的答案。

TLDR:自己處理縮放,例如你的方式。將視圖的layerType切換到軟件以避免模糊的縮放結果。

首先,我完全理解了這種混淆,對於iOS而言,它只是起作用,在Android中你必須擺弄一些尺度。它會更有意義,如果它的工作原理相同,我會喜歡它,也會對其他PaintCode用戶。但這不是一個錯誤。問題是UIKit和android.graphic之間的區別。

在UIKit中,距離是以點爲單位的。這意味着如果你繪製一個直徑爲40分的圓,它在各種iOS設備上的尺寸應該更小。 PaintCode採用了這種約定,並且您在PaintCode的用戶界面中看到的所有數字(如形狀,筆觸寬度或半徑的位置)都是以點爲單位的。由PaintCode生成的繪圖代碼不僅與分辨率無關(即可調整大小/縮放並保持清晰度),而且還與顯示密度無關(在視網膜顯示屏上顯示相同大小,常規顯示和視網膜高清顯示)。代碼沒有特別之處。它看起來像這樣:

NSBezierPath* rectanglePath = [NSBezierPath bezierPathWithRect: NSMakeRect(0, 0, 100, 50)]; 
[NSColor.grayColor setFill]; 
[rectanglePath fill]; 

所以顯示縮放由UIKit處理。隱含的比例也取決於上下文。如果您在某些UIView子類的drawRect:內調用繪圖代碼,它將佔用顯示密度,但如果您在自定義UIImage內繪圖,則需要該圖像的密度。魔法。

然後我們添加了對Android的支持。 android.graphic中的所有度量都以像素表示。 Android不會執行任何UIKit的「顯示密度」魔法。此外,找出密度在繪圖代碼範圍內的方法並不好。你需要訪問資源。所以我們可以將其作爲參數添加到所有繪圖方法中。但是,如果你不打算將圖形發佈到顯示器上,但是你更願意創建一個圖像(你將要發送給你的朋友或者其他什麼)?那麼你不想顯示密度,但圖像密度。 好吧,如果添加一個參數,我們不應該添加資源,而是將密度本身作爲一個float並在每個繪圖方法內部生成縮放。現在如果你不關心密度怎麼辦?如果你所關心的是你的繪圖填滿了矩形並且有最好的分辨率?其實我認爲那通常是這種情況。在我看來,擁有如此多不同的顯示分辨率和顯示密度使得「一種物理尺寸的元素適合所有」方法相當小。所以在大多數情況下,密度參數是無關的。我們決定放棄如何處理規模給用戶的決定。

現在爲縮放圖的模糊性。這是UIKit和android.graphics的另一個區別。所有開發人員都應該明白,CoreGraphics在渲染具有多個對象的大場景時速度不是很快。如果你正在編寫性能敏感的應用程序,你應該考慮使用SpriteKit或Metal。這樣做的好處是,您不會受限於CoreGraphics中的任何操作,而且您幾乎總能得到非常準確的結果。縮放就是一個這樣的例子。你可以申請巨大的規模,結果仍然很脆。如果您想要更多硬件加速,請使用不同的API並自行處理限制(例如,您可以在GPU中適合多大的紋理)。

Android走另一條路。他們的android.graphic api可以在兩種模式下工作 - 沒有硬件加速(他們稱之爲軟件)或硬件加速(他們稱之爲硬件)。它仍然是相同的API,但其中一種硬件模式有一些重大的限制。這包括比例,模糊(因此陰影),一些混合模式等等。 https://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported

,他們決定,每一個視圖將使用硬件模式在默認情況下,如果目標API等級> = 14。當然,你可以將其關閉,並奇蹟般地您的縮放按鈕,將是很好的和尖銳。

我們提到,你需要關閉硬件加速在我們的文檔頁面節「圖層類型」 https://www.paintcodeapp.com/documentation/android 而且,這也是Android文檔https://developer.android.com/guide/topics/graphics/hardware-accel.html#controlling

+0

與已經實施的變更層軟件的伎倆(共同縮放,我把我原來的問題)。非常感謝您的快速回復和大力支持! – HixField

2

我記得有一個類似的問題,在與PaintCode支持人員交談之後,我們想出了一個將DP轉換爲PX的函數。因此,在Android中,考慮到不同的顯示密度,這20個點將被轉換爲「任意」像素。

長話短說,這是PaintCode支持答案的總結:

是Android不支持與設備無關的像素的 繪圖API的事實是iOS和 的不同行爲的原因Android系統。使用UIKit時,輸入的座標是點數,所以 它自己負責顯示密度。在 Android中生成位圖時,需要考慮顯示密度。

這是我創建的功能:

private static PointF convertDPtoPX(float widthDP, float heightDP) { 
    Context context = getAppContext(); 
    DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 
    float widthPX = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, widthDP, metrics); 
    float heightPX = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, heightDP, metrics); 

    return new PointF(widthPX, heightPX); 
} 

這裏是如何調用它的例子:

Bitmap myButton = StyleKit.imageOfMyButton(convertDPtoPX(widthDP, heightDP)); 

當然,在這個例子中我使用的myButton位圖(StyleKit.imageOfMyButton)由於該項目的具體情況。您需要調整示例以適應您的需求。

例如,您可以在PaintCode中爲該外部參數創建radius,從而使每個平臺負責提供其值。喜歡:

// In Android, convert 20DP to 20PX based on the above function. 
// In iOS, just pass 20. 
StyleKitName.drawButton1(canvas, frame, radius) 

我希望這可以幫助。

相關問題