2015-12-03 27 views
6

Wykonałem tę niestandardową komendę, która powinna przypiąć dowolne duble w okręgu. Ale z moją implementacją przekazywana taca jest wyjściem w oryginalnej formie, nie w formie okrągłej.Android: Circular Drawable

public class CircularDrawable extends Drawable { 
    Paint mPaint,xfermodePaint; 
    Drawable mDrawable; 
    int[] vinylCenter = new int[2]; 
    int radius; 
    Bitmap src; 
    PorterDuffXfermode xfermode; 
    Rect rect; 
    Canvas testCanvas; 
    public CircularDrawable(Drawable drawable) { 
     mDrawable = drawable; 
     mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
     mPaint.setColor(0xffffffff); 
     mPaint.setStyle(Paint.Style.FILL); 
     xfermodePaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
     xfermode=new PorterDuffXfermode(PorterDuff.Mode.SRC_IN); 
     xfermodePaint.setXfermode(xfermode); 
     testCanvas=new Canvas(); 
    } 

    @Override 
    public void setBounds(Rect bounds) { 
     super.setBounds(bounds); 
     mDrawable.setBounds(bounds); 
    } 

    @Override 
    public void setBounds(int left, int top, int right, int bottom) { 
     super.setBounds(left, top, right, bottom); 
     mDrawable.setBounds(left, top, right, bottom); 
    } 

    @Override 
    protected void onBoundsChange(Rect bounds) { 
     super.onBoundsChange(bounds); 
     vinylCenter[0] = bounds.width()/2; 
     vinylCenter[1] = bounds.height()/2; 
     radius = (bounds.right - bounds.left)/2; 
     src = Bitmap.createBitmap(bounds.width(), bounds.height(), Bitmap.Config.ARGB_8888); 
     testCanvas.setBitmap(src); 
    } 


    @Override 
    public void draw(Canvas canvas) { 
     canvas.save(); 
     canvas.drawARGB(0, 0, 0, 0); 
     canvas.drawCircle(vinylCenter[0],vinylCenter[1],radius,mPaint); 
     mDrawable.draw(testCanvas); 
     canvas.drawBitmap(src,0f,0f,xfermodePaint); 
    } 



    @Override 
    public void setAlpha(int alpha) {/*ignored*/} 

    @Override 
    public void setColorFilter(ColorFilter colorFilter) {/*ignored*/} 

    @Override 
    public int getOpacity() { 
     /*ignored*/ 
     return 0; 
    } 
} 

Jaki jest mój błąd?

Używam również SquareImageview do wyświetlania tego losowania, które powoduje, że widok jest kwadratowy w onMeasure. To pytanie nie jest przeznaczone do okrągłego podglądu obrazu.

+2

patrz [to ] (http://androidxref.com/6.0.0_r1/xref/frameworks/support/v4/donut/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java) jako odniesienie – pskink

+0

@pskink, ale jest to inna implementacja. Chcę wiedzieć, jaki jest mój błąd w implementacji Porter/Duff. –

+0

jeśli jest kwadratowy oznacza to, że rysujesz cały obszar "DST" ' – pskink

Odpowiedz

3

Kanał nie ma domyślnie włączonego kanału alfa podczas korzystania z trybu Porter/Duff xfermode (jak na moje doświadczenia z tym w Androidzie). Z tego powodu cały obraz (src) jest wynikiem. Porter/Duff xfermode działa w oparciu o kanał alfa.

W wielu wykonaniach Circular Drawable 2 Canvas, z których jedna jest podana jako bitmapa RGB, a druga ma tylko bitmapę alfa z okrągłym maskowaniem. Porter/Duff xfermodeis zostały zastosowane, a wynik jest narysowany na głównym płótnie.

Moim błędem jest to, że nie określam płótna funkcji rysowania, że ​​kanał alfa należy rozważyć przy użyciu warstwy na płótnie dla xfermode.

funkcji draw będzie

@Override 
public void draw(Canvas canvas) { 
    int sc = canvas.saveLayer(null, null, 
        Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | 
        ); 
    canvas.drawCircle(vinylCenter[0],vinylCenter[1],radius,mPaint); 
    mDrawable.draw(testCanvas); 
    canvas.drawBitmap(src,0f,0f,xfermodePaint); 
    canvas.restoreToCount(sc); 
} 

Zapisywanie warstwę wskazuje kanał alfa z flagą, a następnie za pomocą xfermode. Wreszcie przywracając go do jego liczby zapisu.

3

Więc w zasadzie użyć tej metody, aby uzyskać zaokrąglone obrazów narożne

public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) { 
    Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); 
    Canvas canvas = new Canvas(output); 

    final int color = 0xff424242; 
    final Paint paint = new Paint(); 
    final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); 
    final RectF rectF = new RectF(rect); 
    final float roundPx = pixels; 

    paint.setAntiAlias(true); 
    canvas.drawARGB(0, 0, 0, 0); 
    paint.setColor(color); 
    canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 

    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 
    canvas.drawBitmap(bitmap, rect, rect, paint); 

    return output; 

ale jak pan zauważył czasami to nie działa, jak to działa, ale to, co dzieje się przez większość czasu to ImageView może mieć jego zestaw znaków ustawiony na centerCrop i inne typy, co robię, to najpierw kompresję wysokość obrazu do tej samej wysokości i szerokości, co mój widok obrazu, tak aby cały obraz zmieścił się w widoku obrazu i żadne skalowanie nie będzie miało miejsca lub po prostu obliczyłem ile wysokości narożnika do zaokrąglenia za pomocą tej funkcji na podstawie wysokości

więc używam mojego kodu, takich jak: new Bitmap(getRoundedCornerBitmap(bmp, calculatePercentage(5, bmp.getHeight()))); where 5 is 5 wysokości obrazu to daje mi te same krzywe dla wszystkich obrazów czy to niektóre obrazy są większe niż inni `

+0

Kolejne obejście nie zostało zadane. Założenie, które zrobiłeś o scaletype jest złe. Domyślny scaletype to fitCenter. –

+0

@Paritosh Tonk możesz wziąć moją pomoc czy nie moja droga działa idealnie –

+0

Doceniam twoją pomoc. Myśl nie dotyczy pracy. Jego koncepcja i dlaczego tak się dzieje. –

2
For rounded imageview you can use this code 

    public class RoundedImageView extends ImageView { 

    public RoundedImageView(Context context) { 
     super(context); 
     // TODO Auto-generated constructor stub 
    } 

    public RoundedImageView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public RoundedImageView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 

     Drawable drawable = getDrawable(); 

     if (drawable == null) { 
      return; 
     } 

     if (getWidth() == 0 || getHeight() == 0) { 
      return; 
     } 
     Bitmap b = ((BitmapDrawable) drawable).getBitmap(); 
     Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true); 

     int w = getWidth();//, h = getHeight(); 

     Bitmap roundBitmap = getCroppedBitmap(bitmap, w); 
     canvas.drawBitmap(roundBitmap, 0, 0, null); 

    } 

    public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) 
    { 
     Bitmap sbmp; 
     if (bmp.getWidth() != radius || bmp.getHeight() != radius) 
      sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false); 
     else 
      sbmp = bmp; 
     Bitmap output = Bitmap.createBitmap(sbmp.getWidth(), sbmp.getHeight(),Config.ARGB_8888); 
     Canvas canvas = new Canvas(output); 

//  final int color = 0xffa19774; 
     final Paint paint = new Paint(); 
     final Rect rect = new Rect(0, 0, sbmp.getWidth(), sbmp.getHeight()); 

     paint.setAntiAlias(true); 
     paint.setFilterBitmap(true); 
     paint.setDither(true); 
     canvas.drawARGB(0, 0, 0, 0); 
//  paint.setColor(Color.parseColor("#BAB399")); 
     paint.setColor(Color.parseColor("#FF0000")); 
     canvas.drawCircle(sbmp.getWidth()/2 + 0.7f, sbmp.getHeight()/2 + 0.7f, sbmp.getWidth()/2 + 0.1f, paint); 
     paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 
     canvas.drawBitmap(sbmp, rect, rect, paint); 

     return output; 
    } 
} 
4

Jesteś już zoptymalizowany realizacji dla okrągłej rozciągliwej w Pomoc v4 biblioteka:

Google reference

/** 
* A Drawable that wraps a bitmap and can be drawn with rounded corners. You can create a 
* RoundedBitmapDrawable from a file path, an input stream, or from a 
* {@link android.graphics.Bitmap} object. 
* <p> 
* Also see the {@link android.graphics.Bitmap} class, which handles the management and 
* transformation of raw bitmap graphics, and should be used when drawing to a 
* {@link android.graphics.Canvas}. 
* </p> 
*/ 
public abstract class RoundedBitmapDrawable extends Drawable .... 
3
For circular imageview use the below code 

public class RoundedImageView extends ImageView { 

    public RoundedImageView(Context context) { 
     super(context); 
    } 

    public RoundedImageView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public RoundedImageView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     BitmapDrawable drawable = (BitmapDrawable) getDrawable(); 

     if (drawable == null) { 
      return; 
     } 

     if (getWidth() == 0 || getHeight() == 0) { 
      return; 
     } 

     Bitmap fullSizeBitmap = drawable.getBitmap(); 

     int scaledWidth = getMeasuredWidth(); 
     int scaledHeight = getMeasuredHeight(); 

     /* 
     * scaledWidth = scaledWidth/2; scaledHeight = scaledHeight/2; 
     */ 

     Bitmap mScaledBitmap; 
     if (scaledWidth == fullSizeBitmap.getWidth() 
       && scaledHeight == fullSizeBitmap.getHeight()) { 
      mScaledBitmap = fullSizeBitmap; 
     } else { 
      mScaledBitmap = Bitmap.createScaledBitmap(fullSizeBitmap, 
        scaledWidth, scaledHeight, true /* filter */); 
     } 

     // Bitmap roundBitmap = getRoundedCornerBitmap(mScaledBitmap); 

     // Bitmap roundBitmap = getRoundedCornerBitmap(getContext(), 
     // mScaledBitmap, 10, scaledWidth, scaledHeight, false, false, 
     // false, false); 
     // canvas.drawBitmap(roundBitmap, 0, 0, null); 

     Bitmap circleBitmap = getCircledBitmap(mScaledBitmap); 

     canvas.drawBitmap(circleBitmap, 0, 0, null); 

    } 

    public Bitmap getRoundedCornerBitmap(Context context, Bitmap input, 
      int pixels, int w, int h, boolean squareTL, boolean squareTR, 
      boolean squareBL, boolean squareBR) { 

     Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888); 
     Canvas canvas = new Canvas(output); 
     final float densityMultiplier = context.getResources() 
       .getDisplayMetrics().density; 

     final int color = 0xff424242; 

     final Paint paint = new Paint(); 
     final Rect rect = new Rect(0, 0, w, h); 
     final RectF rectF = new RectF(rect); 

     // make sure that our rounded corner is scaled appropriately 
     final float roundPx = pixels * densityMultiplier; 

     paint.setAntiAlias(true); 
     canvas.drawARGB(0, 0, 0, 0); 
     paint.setColor(color); 
     canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 

     // draw rectangles over the corners we want to be square 
     if (squareTL) { 
      canvas.drawRect(0, 0, w/2, h/2, paint); 
     } 
     if (squareTR) { 
      canvas.drawRect(w/2, 0, w, h/2, paint); 
     } 
     if (squareBL) { 
      canvas.drawRect(0, h/2, w/2, h, paint); 
     } 
     if (squareBR) { 
      canvas.drawRect(w/2, h/2, w, h, paint); 
     } 

     paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 
     canvas.drawBitmap(input, 0, 0, paint); 

     return output; 
    } 

    Bitmap getCircledBitmap(Bitmap bitmap) { 

     Bitmap result = Bitmap.createBitmap(bitmap.getWidth(), 
       bitmap.getHeight(), Bitmap.Config.ARGB_8888); 

     Canvas canvas = new Canvas(result); 

     int color = Color.BLUE; 
     Paint paint = new Paint(); 
     Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); 

     paint.setAntiAlias(true); 
     canvas.drawARGB(0, 0, 0, 0); 
     paint.setColor(color); 
     // canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 
     canvas.drawCircle(bitmap.getWidth()/2, bitmap.getHeight()/2, 
       bitmap.getHeight()/2, paint); 

     paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 
     canvas.drawBitmap(bitmap, rect, rect, paint); 

     return result; 
    } 

} 
0

Spróbuj wyłączyć akcelerację sprzętową jeśli używasz PorterDuffXfermode:

W oczywisty dla całej działalności:

<activity android:hardwareAccelerated="false" /> 

lub na konkretnym widokiem na których używasz xfermode:

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);