Lesson 166. Graphics. Creating your own Drawable
Android Lessons

Lesson 166. Graphics. Creating your own Drawable


In this lesson:

– create Drawable

In the past lessons, we looked at some System Drawable ones, now I suggest you learn how to create them yourself. Drawable is an abstract class, and its heirs need to implement 4 of the following methods:

1) public abstract void draw (Canvas canvas) is probably the most important method, because here we are given a canvas and we need to draw on it what our custom Drawable should reflect

2) public abstract int getOpacity () – as far as I understand help, in this method we need to return the transparency value of our Drawable. There are 4 constants in total:

UNKNOWN – transparency is unknown

TRANSPARENT – Drawable will be completely transparent

TRANSLUCENT – Drawable will consist of transparent and opaque sections

OPAQUE – Drawable will be completely opaque

That is, if someone, for example, is planning to draw a bitmap from your Drawable, then it can use the method getOpacity to request transparency, and if you return the constant OPAQUE, it will mean that you can use the RGB_565 config instead of ARGB_8888, that is, do not spend memory bits on transparency. . (See Lesson 157 for more information on configs, bits, and memory.)

3) public abstract void setAlpha (int alpha) – here we are given transparency values ​​and we need to somehow apply this to the final image

4) public abstract void setColorFilter (ColorFilter colorFilter) – similar to the previous one, only the input is not an alpha, but a ColorFilter.

hexagon

Let’s create our own Drawable and in this example it will become clearer how to implement the above 4 methods. For example, let’s create Drawable, which will output a hexagon. the class is called HexagonDrawable and don’t forget to specify that he is the heir to the Drawable class:

import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;

public class HexagonDrawable extends Drawable {
  
  private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  private Path mPath = new Path();
  
  @Override
  public void draw(Canvas canvas) {
    canvas.drawPath(mPath, mPaint);
  }

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

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

  @Override
  public void setColorFilter(ColorFilter colorFilter) {
    mPaint.setColorFilter(colorFilter);
  }
  
  @Override
  protected void onBoundsChange(Rect bounds) {
    super.onBoundsChange(bounds);
    int width = bounds.width();
    int height = bounds.height();
    mPath.reset();
    mPath.moveTo(0, height/2);
    mPath.lineTo(width/4, 0);
    mPath.lineTo(width*3/4, 0);
    mPath.lineTo(width, height/2);
    mPath.lineTo(width*3/4, height);
    mPath.lineTo(width/4, height);
    mPath.close();
  }

}

In the method draw we simply output mPath (which will be formed in another method) to the outline using the mPaint brush.

In the method getOpacity we return TRANSLUCENT because we will have an opaque hexagon and the space remaining Drawable will be transparent. Help, by the way, recommends using TRANSLUCENT if you don’t know exactly what to specify.

methods setAlpha and setColorFilter i just redirect mPaint brushes. Everything is simple here, because I have only one brush, and when drawing, it takes into account the data transmitted to it.

Generally, setAlpha and setColorFilter methods can be implemented and left blank, your Drawable will work without them. But if suddenly (or yourself) will use your Drawable and want to make it transparent or apply ColorFilter, it will not get the expected result because the methods are not implemented.

In addition to the 4 required methods, the onBoundsChange method had to be implemented. This method is called when the size of Drawable changes. So we need to draw a 6-size triangle with Drawable, we need to know its size. Here we get the width and height of Drawable and use them to create a path-figure of a 6-triangle.

Remain in the layout hang View, set it size, for example 200×200 dp and in the code to give it our HexagonDrawable as background

    View view = findViewById(R.id.view);
    Drawable dr = new HexagonDrawable();
    view.setBackgroundDrawable(dr);

result:

We created Drawable, which simply draws a 6-triangle default black. But it looks a little boring, so let’s “add paint” and realize the ability to specify any color to fill the hexagon.

colored hexagon

We will not change the functionality of the already created class, even if it reflects a black hexagon. We will create a new class that will be the heir of HexagonDrawable.

But first, this method will still need to be added to the HexagonDrawable class

  protected Paint getPaint() {
    return mPaint;
  }

It will allow HexagonDrawable heirs to access the brush that draws the hexagon. And, accordingly, by changing the brush settings we will receive changes in the drawing.

Now we create a class ColorHexagonDrawable:

public class ColorHexagonDrawable extends HexagonDrawable {

  public ColorHexagonDrawable(int color) {
    getPaint().setColor(color);
  }

}

It inherits the HexagonDrawable class we created earlier, that is, it will also draw a 6-triangle, but in the constructor we have added the ability to specify the color. Using the getPaint method added to HexagonDrawable, we get a brush and set it to the desired color.

Let’s create a ColorHexagonDrawable object with a green color and let’s check at the same time whether transparency works:

    View view = findViewById(R.id.view);
    Drawable dr = new ColorHexagonDrawable(Color.GREEN);
    dr.setAlpha(50);
    view.setBackgroundDrawable(dr);

result:

We have specified green and transparency values. Both of these values ​​were transmitted to the brush, which is what we see as a result on the screen – a green translucent hexagon.

So now we have as many as two of our own Drawable: one draws a black hexagon and the other also lets you specify a color. Let’s make a third one that will take Bitmap and make a hexagon from it.

Hexagon from the picture

we create a class BitmapHexagonDrawableInheriting HexagonDrawable

import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Rect;
import android.graphics.Shader;

public class BitmapHexagonDrawable extends HexagonDrawable {
  
  Bitmap mOriginBitmap;
  
  public BitmapHexagonDrawable(Bitmap bitmap) {
    mOriginBitmap = bitmap;
  }
  
  @Override
  protected void onBoundsChange(Rect bounds) {
    super.onBoundsChange(bounds);
    Bitmap bitmap = Bitmap.createScaledBitmap(mOriginBitmap, bounds.width(), bounds.height(), true);
    BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
    getPaint().setShader(shader);
  }

}

We pass Bitmap to the constructor, and onBoundsChange take Drawable sizes, create Bitmap of the same size, create a shader on it and pass it to the brush. You can read more about shaders in Lesson 165.

For example, I’ll take this picture

Put it in the res folder named picture.png. Now we create Bitmap from it and pass it to the constructor BitmapHexagonDrawable.

    View view = findViewById(R.id.view);
    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.picture);
    Drawable dr = new BitmapHexagonDrawable(bitmap);
    view.setBackgroundDrawable(dr);

result:

The picture became a hexagonal shape.




Discuss in the forum [1 reply]

Leave a Reply

Your email address will not be published. Required fields are marked *