2015-10-30 321 views
0

我寫了一個小類,可以用它來創建自定義繪圖。大多數情況下,一切都按預期工作,但是當展示幾乎「像素完美」的可繪圖時,我真的不知道如何得到適當的解決方案。一個合適的解決方案是在底層形狀上獲得100%居中的字符/文本。任何建議是受歡迎的。提前致謝。可繪製(密度)的最佳實踐

這裏是類:

public class DrawableSquareLetter extends Drawable { 

    private final Paint paint; 
    private Paint textPaint; 
    private final Builder builder; 


    public DrawableSquareLetter(Builder builder) { 
     this.builder = builder; 
     paint = new Paint(); 
     paint.setAntiAlias(true); 
     paint.setStyle(Paint.Style.FILL); 
     paint.setColor(builder.color); 

     if (builder.applySurfaceShadow) { 
      paint.setShadowLayer(
        DeviceUtils.dp2px(4), 
        DeviceUtils.dp2px(2), 
        DeviceUtils.dp2px(2), 
        Color.parseColor(MaterialColor.GREY_900)); 
     } 


     textPaint = new Paint(); 
     textPaint.setColor(builder.textColor); 
     textPaint.setAntiAlias(true); 
     textPaint.setFakeBoldText(builder.isBold); 
     textPaint.setStyle(Paint.Style.FILL); 
     textPaint.setTypeface(builder.typeface); 
     textPaint.setTextAlign(Paint.Align.CENTER); 

     if (builder.applyTextShadow) { 
      textPaint.setShadowLayer(
        DeviceUtils.dp2px(2), 
        DeviceUtils.dp2px(1), 
        DeviceUtils.dp2px(1), 
        Color.parseColor(MaterialColor.GREY_800)); 
     } 

    } 


    @Override 
    public void draw(Canvas canvas) { 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
      canvas.drawRoundRect(0, 0, builder.size, builder.size, builder.rounded, builder.rounded, paint); 
     } else canvas.drawRect(0, 0, builder.size, builder.size, paint); 

     if (builder.textSize == -1) { 
      textPaint.setTextSize(builder.size * .80f); 
     } else textPaint.setTextSize(builder.textSize); 

     float width = builder.size; 
     float height = builder.size; 

     String text = builder.isUpperCase ? builder.text.toUpperCase() : builder.text; 
     canvas.drawText(text, width/2f, height/2f - (((textPaint.descent() + textPaint.ascent()))/2f), textPaint); 
    } 


    @Override 
    public void setAlpha(int alpha) { 
     paint.setAlpha(alpha); 
    } 


    @Override 
    public void setColorFilter(ColorFilter colorFilter) { 
     paint.setColorFilter(colorFilter); 
    } 


    @Override 
    public int getOpacity() { 
     return PixelFormat.TRANSLUCENT; 
    } 


    public static class Builder { 

     private final float size; 
     private final int color; 
     private String tag = ""; 
     private float rounded; 
     private final String text; 
     private int textColor = Color.BLACK; 
     private float textSize = -1; 
     private Typeface typeface = Typeface.DEFAULT; 

     private boolean isUpperCase = true; 
     private boolean isBold = true; 
     private boolean applyTextShadow = true; 
     private boolean applySurfaceShadow = true; 


     public Builder(int sizeDp, int color, String text) { 
      this.text = text; 
      this.size = DeviceUtils.dp2px(sizeDp); 
      this.color = color; 
     } 


     public Builder(int sizeDp, String color, String text) { 
      this.text = text; 
      this.size = DeviceUtils.dp2px(sizeDp); 
      this.color = Color.parseColor(color); 
     } 


     public Builder textSize(float textSize) { 
      this.textSize = DeviceUtils.sp2px(textSize); 
      return this; 
     } 


     public Builder rounded(int radiusDp) { 
      this.rounded = DeviceUtils.dp2px(radiusDp); 
      return this; 
     } 


     public Builder textColor(int textColor) { 
      this.textColor = textColor; 
      return this; 
     } 


     public Builder textColor(String textColor) { 
      this.textColor = Color.parseColor(textColor); 
      return this; 
     } 


     public Builder typeface(Typeface typeface) { 
      this.typeface = typeface; 
      return this; 
     } 


     public Builder disableUpperCase() { 
      this.isUpperCase = false; 
      return this; 
     } 


     public Builder disableBold() { 
      this.isBold = false; 
      return this; 
     } 


     public Builder disableShadowOnSurface() { 
      this.applySurfaceShadow = false; 
      return this; 
     } 


     public Builder disableShadowOnText() { 
      this.applyTextShadow = false; 
      return this; 
     } 


     public Builder setTag(String tag) { 
      this.tag = tag; 
      return this; 
     } 


     public DrawableSquareLetter build() { 
      return new DrawableSquareLetter(this); 
     } 


     public void show(ImageView imageView) { 
      imageView.setImageDrawable(this.build()); 
     } 
    } 


    public String getTag() { return builder.tag; } 

} 

nexus 5 genymotion enter image description here

+0

它尚未居中呢? – Nanoc

+0

是的,但沒有完全居中。在其他密度下,您將認識到更明顯的差異。 –

+2

使用'Paint#getTextBounds' – pskink

回答

1

如果要居中底層形狀的文字,你需要繪製文本在正確的地方和你需要使用Paint.getTextBounds (String text, int start, int end, Rect bounds)

public void getTextBounds(String text,int start,int end,Rect )

返回界限(由調用者分配) 包含所有字符的最小矩形,隱含起點爲(0,0)。

一旦您執行此方法,您將獲得bounds中的信息。所有你需要做的就是在你的Drawable,在那裏你計算出X/Y座標進行drawText()(在此基礎上bounds RECT)的draw方法寫一個邏輯。

+1

不需要'translate',因爲你可以直接指定'x'和'y'座標'drawText'調用 – pskink

+0

是的,這樣做更有意義。謝謝。 – Henry