Android custom View image (imitating a 360 refresh ball to customize a SeekBar)
Overview:
360 the refresh ball of the security guard (just call it refresh the ball, because I really don't know what it is called, not the refresh ball in dota !!), It is as lively and cute as water. It seems simple and not easy to write. This routine only implements some of its functions. To be honest, compared with the refresh ball of 360, the gap is still very large. I am a little frustrated.
Knowledge required for this course includes: android custom View, custom canvas, path, Bitmap, and Handler
Result demonstration:
Damo
Public class MyPathView extends View {private int width; private int height; private int progress; private int maxProgress = 100; private Path mPath; private Paint mPaintCircle; private Paint mPaintWave; private Paint mPaintText; private Bitmap mBitmapBubble; private Canvas mCanvasBitmap; private int size = 0; // water fluctuation margin private int count; // water flow distance private boolean isAdd = true; private static final int START_WAVE = 0x21; public int getProgress () {return progress;} public void setProgress (int progress) {this. progress = progress; invalidate ();} public int getMaxProgress () {return maxProgress;} public void setMaxProgress (int maxProgress) {this. maxProgress = maxProgress;} private Handler handler = new Handler () {@ Override public void handleMessage (Message msg) {super. handleMessage (msg); switch (msg. what) {case START_WAVE: count + = 30; if (count >=180) {count = 0;} if (isAdd) {size + = 7; if (size> 41) {isAdd = false ;}} else {size-= 7; if (size <=-41) {isAdd = true ;}} invalidate (); sendEmptyMessageDelayed (START_WAVE, 100 ); break ;}}; public MyPathView (Context context) {super (context) ;}public MyPathView (Context context, AttributeSet attrs) {super (context, attrs ); mPaintCircle = new Paint (); mPaintCircle. setStyle (Paint. style. FILL_AND_STROKE); mPaintCircle. setColor (Color. argb (0X4f, 0x4d, 0x4d, 0xff); mPaintText = new Paint (); mPaintText. setColor (Color. WHITE); mPaintText. setTextSize (50); mPaintText. setTextAlign (Paint. align. CENTER); mPaintWave = new Paint (); mPaintWave. setColor (Color. argb (0xaa, 0xff, 0x7c, 0x00); mPaintWave. setStyle (Paint. style. FILL); // The non-overlapping part is not displayed, and the overlapping part shows itself porterduxfermode mode = new porterduxfermode (PorterDuff. mode. SRC_ATOP); mPaintWave. setXfermode (mode); mPath = new Path (); handler. sendEmptyMessageDelayed (START_WAVE, 1000) ;}@ Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {super. onMeasure (widthMeasureSpec, heightMeasureSpec); width = getDefaultSize (rows (), widthMeasureSpec); height = getDefaultSize (rows (), heightMeasureSpec); rows (width, height); rows = Bitmap. createBitmap (width, height, Bitmap. config. ARGB_8888); mCanvasBitmap = new Canvas (mBitmapBubble);} @ Override protected void onDraw (Canvas canvas) {super. onDraw (canvas); mPath. reset (); // canvas. drawColor (Color. argb (0xaa, 0x88, 0x7e, 0x7f); // custom color mCanvasBitmap. drawCircle (width/2, height/2,200, mPaintCircle); mPath. reset (); // circle a rectangle with path to include water waves and balls in mPath. moveTo (width/2 + 200, height/2 + 200-progress/maxProgress * 400); mPath. lineTo (width/2 + 200, height/2 + 200); mPath. lineTo (0, height/2 + 200); mPath. lineTo (0, height/2 + 200-progress/maxProgress * 400);/* draw a wave simulating flow * // when count increases, the re-painting will display the forward flow effect. The value of count cannot be greater than width/2-200 mPath. lineTo (count, height/2 + 200-(float) SS/maxProgress * 400); // mPath. moveTo (count, 200); // The size changes from large to small, from small to large, and the Ripper effect will be generated during repainting (int I = 0; I <20; I ++) {/* The rQuadTo () method will automatically move to the next position each time. The parameters are horizontal amplitude, vertical amplitude, horizontal displacement, and disposal displacement */mPath. rQuadTo (20, size, 90, 0); mPath. rQuadTo (20,-size, 90, 0);} mPath. close (); mCanvasBitmap. drawPath (mPath, mPaintWave); canvas. drawBitmap (mBitmapBubble, 0, 0, null); // draw the text, canvas of the current progress. drawText (progress * 100/maxProgress + %, width/2, height/2, mPaintText );}}
Custom View called by the main activity:
Public class MainActivity extends Activity {private int progress; private Button mButtonStart; private MyPathView myPathView; private static final int DOWNLOAD_UPDATE = 0x99; // simulate the download of private Handler mHandler = new Handler () {@ Override public void handleMessage (Message msg) {super. handleMessage (msg); // process msg switch (msg. what) {case DOWNLOAD_UPDATE: progress + = 1; // when progress is greater than maxProgress, the method if (progress <= myPathView. getMaxProgress () {myPathView. setProgress (progress); // set the new progress sendEmptyMessageDelayed (DOWNLOAD_UPDATE, 100); // send handler} break every 100 milliseconds ;}}}; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); mButtonStart = (Button) findViewById (R. id. button_start); myPathView = (MyPathView) findViewById (R. id. progress_view_first); mButtonStart. setOnClickListener (new View. onClickListener () {@ Override public void onClick (View v) {// send a delayed empty message to handler, and send mHandler after 1000 milliseconds. sendEmptyMessageDelayed (DOWNLOAD_UPDATE, 1000 );}});}}