Android View custom Rangeseekbar range Selector Walk on the View advanced path

Source: Internet
Author: User

There was a similar demand in the brothers project in the previous time group.



I see brothers suffering, unkind. And because of the indifferent, intends to an armchair. Is love and hate tangled, the day God said to me: nothing more to build some wheels, your life will have a lot of harvest. I was so touched by this chicken soup that I decided to save my brother from the fiery heat of the aquatic life.



Overriding the Onmeasure decision itself size


It is obvious that when the limit of the range that can be dragged is zero, that is, the Rangeseebar normal display can accept the limit, a cursory look: Width > 2 * Height

@Overrideprotected void onmeasure (int widthmeasurespec, int heightmeasurespec) {int widthsize = Measurespec.getsize ( WIDTHMEASURESPEC); int heightsize = Measurespec.getsize (Heightmeasurespec); if (Heightsize * 2 > Widthsize) { Setmeasureddimension (Widthsize, WIDTHSIZE/2);} else {super.onmeasure (widthmeasurespec, Heightmeasurespec);}}

draw a drag bar background everything starts from the simple first

public class Rangeseekbar extends View {private paint paint = new paint (Paint.anti_alias_flag);    private int linetop, Linebottom, Lineleft, lineright;    private int linecorners;    private int linewidth;    Private RECTF line = new RECTF ();    Public Rangeseekbar (Context context) {This (context, NULL);    } public Rangeseekbar (context context, AttributeSet Attrs) {Super (context, attrs); } @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {int widthsize = Measuresp        Ec.getsize (WIDTHMEASURESPEC);        int heightsize = measurespec.getsize (Heightmeasurespec);        if (Heightsize * 2 > Widthsize) {setmeasureddimension (widthsize, (int) (WIDTHSIZE/2));        } else {super.onmeasure (widthmeasurespec, Heightmeasurespec); }} @Override protected void onsizechanged (int w, int h, int oldw, int oldh) {super.onsizechanged (W, H, O        LDW, OLDH); int Seekbarradius = H/2;        /** * Property Left Right top bottom describes the position of the Seekbar button * Blue after setting the three-dimensional RECTF line background according to their preset * Linecorn        ERs sleek edges seem to look better than right angles */lineleft = Seekbarradius;        Lineright = W-seekbarradius;        Linetop = SEEKBARRADIUS-SEEKBARRADIUS/4;        Linebottom = Seekbarradius + Seekbarradius/4;        LineWidth = Lineright-lineleft;        Line.set (Lineleft, Linetop, Lineright, Linebottom);    Linecorners = (int) ((linebottom-linetop) * 0.45f);        } @Override protected void OnDraw (canvas canvas) {super.ondraw (canvas);        Paint.setstyle (Paint.Style.FILL);        Paint.setcolor (0XFFD7D7D7);    Canvas.drawroundrect (line, linecorners, linecorners, paint); }}

It is obvious that the Seekbarradius is designed to be the radius of the Seekbar button, with a value of Rangeseekbar half its height. So that the Seekbar button center of the default state can be pressed to the start and end of the background bar
The starting and ending points of the background bar are, of course, shifted from one radius to the inside relative to the width of each.


Drag the stage is ready, Seekbar button radius is also set. Yielded, the next step is to draw the Seekbar.


Seekbar buttons are excellent for owning objects
A rough thought: Buttons have color, size, discoloration, be drawn, collision detection, boundary detection, drag and so on, the most critical is that there are many. So the Seekbar button can be said to be a complex collection, it is time to send the object.


Private class SeekBar {int widthsize;int left, right, top, bottom; Bitmap bmp;/** * When the Rangeseekbar size changes, the Seekbar button size varies * * @param the relative position of the X center of the CenterX seekbar button in Rangeseekbar * @param cen The relative position of the Y center of the Tery seekbar button in Rangeseekbar * @param heightsize Rangeseekbar expects Seekbar to have a height */void onsizechanged (int CenterX , int centery, int heightsize) {/** * property left Right Top bottom describes the location of the Seekbar button <br> * widthsize = heightsize * 0.8f can be See button The actual area is a rectangle instead of a square * Circle button Why do you occupy a rectangular area? Because of the button shadow effect. Don't you have a shadow? I'm not * so onmeasure twice times the width?  I will not */widthsize = (int) (heightsize * 0.8f); left = Centerx-widthsize/2;right = CenterX + widthsize/2;top = centery- Heightsize/2;bottom = centery + heightsize/2;bmp = Bitmap.createbitmap (Widthsize, Heightsize, Bitmap.Config.ARGB_8888 ) int bmpcenterx = Bmp.getwidth ()/2;int bmpcentery = Bmp.getheight ()/2;int Bmpradius = (int) (widthsize * 0.5f); Canvas Defaultcanvas = new canvas (BMP); Paint Defaultpaint = new paint (paint.anti_alias_flag);//Draw Shadowdefaultpaint.setstyle (PaiNt. Style.fill); int barshadowradius = (int) (Bmpradius * 0.95f);d efaultcanvas.save ();d efaultcanvas.translate (0, Bmpradius * 0.25f); Radialgradient shadowgradient = new Radialgradient (Bmpcenterx, Bmpcentery, Barshadowradius, Color.BLACK, Color.transparent, Shader.TileMode.CLAMP);d Efaultpaint.setshader (shadowgradient);d efaultcanvas.drawcircle ( Bmpcenterx, Bmpcentery, Barshadowradius, Defaultpaint);d efaultpaint.setshader (null);d efaultcanvas.restore ();// Draw Bodydefaultpaint.setstyle (Paint.Style.FILL);d Efaultpaint.setcolor (0xFFFFFFFF);d efaultcanvas.drawcircle ( Bmpcenterx, Bmpcentery, Bmpradius, defaultpaint);//Draw Borderdefaultpaint.setstyle (Paint.Style.STROKE); Defaultpaint.setcolor (0XFFD7D7D7);d efaultcanvas.drawcircle (Bmpcenterx, Bmpcentery, Bmpradius, defaultPaint);}    void Draw (Canvas canvas) {canvas.drawbitmap (BMP, left, top, null); }}


public class Rangeseekbar extends View {    private SeekBar SeekBar = new SeekBar ();    Private class SeekBar {        ...    }    @Override    protected void onsizechanged (int w, int h, int oldw, int oldh) {        super.onsizechanged (W, H, OLDW, OLDH); C7/>int Seekbarradius = H/2;        ...//seekBar button size        seekbar.onsizechanged (Seekbarradius, Seekbarradius, h)    when Rangeseekbar determines size @Override    protected void OnDraw (canvas canvas) {        super.ondraw (canvas);        ...//Draw SeekBar button        Seekbar.draw (canvas) when Rangeseekbar is drawn;}    }

It's a step closer to success.



Ontouchevent Touch Monitor let Seekbar button move.

@Overridepublic boolean ontouchevent (Motionevent event) {switch (event.getaction ()) {case Motionevent.action_down: Boolean touchresult = false;//to detect whether the finger falls on the current seekbar. That is, when declaring seekbar, use the internal   if (Seekbar.collide (event)) {Touchresult = true) of the area described by the left, top, right, bottom property;  return touchresult;case MotionEvent.ACTION_MOVE:float percent;float x = Event.getx (); if (x <= lineleft) {percent = 0;} else if (x >= lineright) {percent = 1;} else {percent = (x-lineleft) * 1f/(linewidth);} Seekbar button slide Seekbar.slide (percent) according to the current finger sliding on the drag bar; invalidate (); break;} Return Super.ontouchevent (event);}


Private class SeekBar {int linewidth;//drag bar width to get float currpercent;int left at onsizechanged time, right, top, Bottom;boolean C Ollide (Motionevent event) {float x = Event.getx (); Float y = event.gety (); int offset = (int) (linewidth * currpercent); Retu RN x > left + offset && x < right + offset && y > top && y < bottom;} void slide (float percent) {if (Percent < 0) percent = 0;else if (Percent > 1) percent = 1;currpercent = percent;} void Draw (canvas canvas) {int offset = (int) (linewidth * currpercent); Canvas.save (); canvas.translate (offset, 0); Canvas.drawbitmap (BMP, left, top, null); Canvas.restore ();}}


A better visual experience
At this point, the seekbar is lifeless when pressed, and the next step is to add a strong visual feedback.
Then the lazy way of onsizechanged preset buttons is GG, because the Seekbar UI effect needs to change with the touch state.
First, get this change in ontouchevent.

@Overridepublic boolean ontouchevent (Motionevent event) {switch (event.getaction ()) {case Motionevent.action_move: seekbar.material = seekbar.material >= 1? 1:seekbar.material + 0.1f;...invalidate (); Break;case MotionEvent.ACTION_CANCEL:case motionevent.action_up: Seekbar.materialrestore (); break;} Return Super.ontouchevent (event);}

Then respond to this change in the Seekbar button

Private class SeekBar {float material = 0; Valueanimator anim;final typeevaluator<integer> te = new typeevaluator<integer> () {@Overridepublic Integer Evaluate (float fraction, integer startvalue, integer endvalue) {int alpha = (int) (Color.alpha (startvalue) + fraction * (C Olor.alpha (Endvalue)-Color.alpha (Startvalue)); int red = (int) (Color.Red (startvalue) + fraction * (color.red (EndValue) )-Color.Red (Startvalue)); int green = (int) (Color.green (startvalue) + fraction * (Color.green (Endvalue)-Color.green (s Tartvalue)); int blue = (int) (Color.Blue (startvalue) + fraction * (Color.Blue (Endvalue)-Color.Blue (Startvalue))); Return Color.argb (alpha, red, green, blue);}; void Draw (canvas canvas) {int offset = (int) (linewidth * currpercent); Canvas.save (); Canvas.translate (left, 0); Canvas.translate (offset, 0);d rawdefault (canvas); Canvas.restore ();} private void Drawdefault (canvas canvas) {int CenterX = Widthsize/2;int CenterY = heightsize/2;int radius = (int) (Widt Hsize * 0.5f);Draw Shadowdefaultpaint.setstyle (Paint.Style.FILL); Canvas.save () canvas.translate (0, RADIUS * 0.25f); Canvas.scale (1 + (0.1f * material), 1 + (0.1f * material), CenterX, CenterY);d Efaultpaint.setshader (shadowgradient); Canva S.drawcircle (CenterX, CenterY, radius, defaultpaint);d efaultpaint.setshader (null); Canvas.restore ();//Draw Bodydefaultpaint.setstyle (Paint.Style.FILL);d Efaultpaint.setcolor (te.evaluate (material, 0xFFFFFFFF, 0xffe7e7e7)) ; Canvas.drawcircle (CenterX, CenterY, radius, defaultpaint);//Draw Borderdefaultpaint.setstyle (Paint.Style.STROKE); Defaultpaint.setcolor (0XFFD7D7D7); Canvas.drawcircle (CenterX, CenterY, radius, defaultpaint);} private void Materialrestore () {if (anim! = null) Anim.cancel (); anim = valueanimator.offloat (material, 0); Anim.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Overridepublic void Onanimationupdate ( Valueanimator animation) {material = (float) animation.getanimatedvalue (); invalidate ();}); Anim.addlistener (New Animatorlisteneradapter ({@Overridepublic void Onanimationend (Animator animation) {material = 0;invalidate ();}}); Anim.start ();}}

The logic to draw the BMP directly in the draw method is replaced with the Drawdefault
So Drawdefault's internal logic is basically the same as the pre-fabricated BMP, the only two difference is that the shadow shadow do a scale processing, the button body color to do a gradient processing
Materialrestore that is, when the user's finger is lifted and a thread is opened, the state is gradually initialized



Range
Range means scope, but even knowing that doesn't seem to have any eggs _ (: 3"∠) _
So in order to understand the law, the baby hard groping. Finally found



If they all have their own fixed sliding range, the Seekbar button on the right is the left Seekbar button to the right to pan the Seekbar button width.

public class Rangeseekbar extends View {private SeekBar LEFTSB = new SeekBar ();    Private SeekBar RIGHTSB = new SeekBar ();    /** * is used to record the current user touch the end is which SB */private SeekBar Currtouch; @Override protected void onsizechanged (int w, int h, int oldw, int oldh) {super.onsizechanged (W, H, OLDW, OLDH)        ;        ...//RIGHTSB just like the analysis, tightly affixed to LEFTSB's right rightsb.left + = leftsb.widthsize;    Rightsb.right + = Leftsb.widthsize;        } @Override protected void OnDraw (canvas canvas) {super.ondraw (canvas);        ... leftsb.draw (canvas);    Rightsb.draw (canvas); } @Override public boolean ontouchevent (Motionevent event) {switch (event.getaction ()) {case Mot                IonEvent.ACTION_DOWN:boolean Touchresult = false; /** * Why not detect LEFTSB First and detect RIGHTSB first? Why? ('? ')              ) */if (Rightsb.collide (event)) {Currtouch = RIGHTSB;      Touchresult = true;                    } else if (Leftsb.collide (event)) {Currtouch = LEFTSB;                Touchresult = true;            } return Touchresult;                Case MotionEvent.ACTION_MOVE:float percent;                float x = Event.getx ();                    if (Currtouch = = LEFTSB) {if (x < lineleft) {percent = 0;                    } else {percent = (x-lineleft) * 1f/(linewidth-rightsb.widthsize);                    } if (Percent > rightsb.currpercent) {percent = Rightsb.currpercent;                } leftsb.slide (percent);                    } else if (Currtouch = = RIGHTSB) {if (x > Lineright) {percent = 1; } else {percent = (x-lineleft-leftsb.widthsize) * 1f/(LINEWIDTH-LEFTSB. widthsize);                    } if (Percent < leftsb.currpercent) {percent = Leftsb.currpercent;                } rightsb.slide (percent);                } invalidate ();        Break    } return Super.ontouchevent (event); }}

By touching the values of some properties, drawing the corresponding UI effect through the values of these properties, routines are all routines
Then after the Switchbutton, it is a re-revision of the routine


So what can this baby's Rangeseekbar do?
supports negative numbers


Support reserved (reserved) Range

What is a reserved (reserved) range? Like that, you know. Imaginative achievement here, inexpressible. (? ? ?)?


For example, now 2 buttons are reserved for a distance, of course, you can keep n


Support scale mode

Of course the scale is supported and the reserved range is supported


Support for custom UI button style background color



There seems to be less pressing state changes


How do I use it?
[Poke me to rangeseekbar use tutorial]


If you like this article, you can also make a reward, the amount of unlimited



Copyright NOTICE: Welcome reprint, but please respect the author's labor results, reprint please indicate the source-->http://blog.csdn.net/bfbx5173 QQ Group: 274306954



Android View custom Rangeseekbar range Selector Walk on the View advanced path

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.