Android custom control implementation

Source: Internet
Author: User
Tags border image

Android custom control implementation

Recently, I wrote a custom countdown control in the project. The result is that after the countdown starts, the red heart gradually fills up. The effect is as follows:

 

There are two parts: timer and Bitmap.

The Timer uses Timer and TimerTask to execute the run function of TimerTask every second to re-paint the control. The Code is as follows:

mTimer = new Timer();mTimerTask = new TimerTask() {@Overridepublic void run() {postInvalidate();synchronized (this) {if (index > 59) {index = 1;mTimer.cancel();}index++;}}};mTimer.schedule(mTimerTask, 1000, 1000);

The idea of drawing is probably:

 

1. parse the Bitmap from the image resource to obtain its Width and Height;

2. Reload the onMeasure and onSizeChanged functions to set and obtain the width and height of the control;

3. Use porterduxfermode to obtain the Bitmap;

4. Reload the onDraw function. In the function, scale the Bitmap obtained in the previous step to the control size to display it.

 

Next let's take a look at several important parts, and the rest of the code will be attached at the end.

1. Reload the onMeasure function to measure the widget size.

@Overridepublic void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int resultW = 0;if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {resultW = MeasureSpec.getSize(widthMeasureSpec);} else {if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) {resultW = Math.min(bWidth,MeasureSpec.getSize(widthMeasureSpec));}}int resultH = 0;if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {resultH = MeasureSpec.getSize(heightMeasureSpec);} else {if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {resultH = Math.min(bHeight,MeasureSpec.getSize(heightMeasureSpec));}}setMeasuredDimension(resultW, resultH);}

If I set the following in the xml file:
  
 
We set the width and height of the control to a specific value: 100dp, so the getMode of widthMeasureSpec/heightMeasureSpec obtained by the onMeasure function when the width of the measurement control is high is

 

MeasureSpec. EXACTLY, the width and height of the control is getSize, which is the configured 100dp.

If we configure the following in xml:

  
 
In this case, the getMode of widthMeasureSpec/heightMeasureSpec is MeasureSpec. AT_MOST. In this case, the width and height of the control are smaller than those of the image resource width (or height) and the remaining width (or height) in the parent container.

 

.

2. Obtain the width and height of the control in the onSizeChanged function.

@Overridepublic void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);width = w;height = h;bm = Bitmap.createBitmap(bWidth, bHeight, Bitmap.Config.ARGB_8888);mCanvas = new Canvas(bm);}

Int w and int h are the width and height of the control, respectively.

 

3. In onDraw, the expected Bitmap is obtained through the combination of images.

 

@ Overridepublic void onDraw (Canvas canvas) {canvas. drawBitmap (Bitmap. createScaledBitmap (makeBitmap (), width, height, true), 0, 0, mPaint);} // draw Bitmappublic Bitmap makeBitmap () {// draw the underlying image mCanvas first. drawBitmap (charm, 0, 0, mPaint); int I = mCanvas. saveLayer (0, 0, bm. getWidth (), bm. getHeight (), null, Canvas. ALL_SAVE_FLAG); mPaint. setColor (Color. RED); Log. I ("GrownHeart", "onDraw: index =" + index); mCanvas. drawRect (new RectF (0f, (60-index) * H, bm. getWidth (), bm. getHeight (), mPaint); mPaint. setXfermode (modeIn); mCanvas. drawBitmap (charm_on, 0, 0, mPaint); mPaint. setXfermode (null); mCanvas. restoreToCount (I); return bm ;}

 

The border chart and solid chart are as follows:

First, draw the border image to Bitmap, then create a Canvas layer, and draw a red rectangle on the layer. The height of the rectangle changes each time. Then set the Piant image mixed mode, mPaint. setXfermode (new

Porterduxfermode (PorterDuff. Mode. DST_IN). Then, draw the solid graph into the layer to obtain the overlapping area. Then, store the restore drawn on the layer. Finally, use createScaledBitmap

The Bitmap is scaled to the control size and displayed.


Source code

Public class GrownHeart extends View {public Timer mTimer; public TimerTask mTimerTask; public int bWidth; // Bitmap width public int bHeight; // Bitmap height public int width; // control width public int height; // control height public Bitmap charm; // resource Bitmap public Bitmap charm_on; // resource Bitmap public Bitmap bm; public Canvas mCanvas; public Paint mPaint; public float H; private static int index; public static final porterduxfermode modeIn; public static final porterduxfermode modeOut; static {modeIn = new porterduxfermode (PorterDuff. mode. DST_IN); modeOut = new porterduxfermode (PorterDuff. mode. SRC_IN);} public GrownHeart (Context context) {super (context); init ();} public GrownHeart (Context context, AttributeSet attrs) {super (context, attrs ); init ();} public void init () {mTimer = new Timer (); mTimerTask = new TimerTask () {@ Overridepublic void run () {postInvalidate (); synchronized (this) {if (index> 59) {index = 1; mTimer. cancel ();} Log. I ("GrownHeart", "TimerTask1: index =" + index); index ++; Log. I ("GrownHeart", "TimerTask2: index =" + index) ;}}; charm = BitmapFactory. decodeResource (getResources (), R. drawable. chatroom_charm ). copy (Bitmap. config. ARGB_8888, true); charm_on = BitmapFactory. decodeResource (getResources (), R. drawable. chatroom_charm_on ). copy (Bitmap. config. ARGB_8888, true); bWidth = charm_on.getWidth (); bHeight = charm_on.getHeight (); H = bHeight/60F; index = 1; mPaint = new Paint (); mPaint. setAntiAlias (true); mPaint. setFilterBitmap (false);} public void startTimer () {mTimer. schedule (mTimerTask, 1000,100 0) ;}@ Overridepublic void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {int resultW = 0; if (MeasureSpec. getMode (widthMeasureSpec) = MeasureSpec. EXACTLY) {resultW = MeasureSpec. getSize (widthMeasureSpec);} else {if (MeasureSpec. getMode (widthMeasureSpec) = MeasureSpec. AT_MOST) {resultW = Math. min (bWidth, MeasureSpec. getSize (widthMeasureSpec) ;}} int resultH = 0; if (MeasureSpec. getMode (heightMeasureSpec) = MeasureSpec. EXACTLY) {resultH = MeasureSpec. getSize (heightMeasureSpec);} else {if (MeasureSpec. getMode (heightMeasureSpec) = MeasureSpec. AT_MOST) {resultH = Math. min (bHeight, MeasureSpec. getSize (heightMeasureSpec) ;}} setMeasuredDimension (resultW, resultH) ;}@ Overridepublic void onSizeChanged (int w, int h, int oldw, int oldh) {super. onSizeChanged (w, h, oldw, oldh); width = w; height = h; bm = Bitmap. createBitmap (bWidth, bHeight, Bitmap. config. ARGB_8888); mCanvas = new Canvas (bm);} // draw Bitmappublic Bitmap makeBitmap () {// draw the underlying image mCanvas first. drawBitmap (charm, 0, 0, mPaint); int I = mCanvas. saveLayer (0, 0, bm. getWidth (), bm. getHeight (), null, Canvas. ALL_SAVE_FLAG); mPaint. setColor (Color. RED); Log. I ("GrownHeart", "onDraw: index =" + index); mCanvas. drawRect (new RectF (0f, (60-index) * H, bm. getWidth (), bm. getHeight (), mPaint); mPaint. setXfermode (modeIn); mCanvas. drawBitmap (charm_on, 0, 0, mPaint); mPaint. setXfermode (null); mCanvas. restoreToCount (I); return bm ;}@ Overridepublic void onDraw (Canvas canvas) {canvas. drawBitmap (Bitmap. createScaledBitmap (makeBitmap (), width, height, true), 0, 0, mPaint );}}

          
                    
  
 

public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);GrownHeart grownHeart=(GrownHeart)findViewById(R.id.grownHeart);grownHeart.startTimer();}}


 

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.