java - Setting width of SeekBar to make "swipe to unlock" effect -
i attempting make swipe unlock feature using seekbar. aiming shown here:
this composed of 2 images, background, , button. put both background , seekbar in framelayout seekbar should sit on top of background.
like so:
<linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" > <textview android:id="@+id/textview1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:text="testing 123..." /> <framelayout android:layout_height="wrap_content" android:layout_width="wrap_content" > <imageview android:id="@+id/imageview01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaletype="center" android:src="@drawable/unlockback" /> <seekbar android:id="@+id/myseek" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="false" android:max="100" android:progressdrawable="@android:color/transparent" android:thumb="@drawable/unlockbut" /> </framelayout> </linearlayout>
unfortunately end result looks (in eclipse):
i seem unable make seekbar match size of framelayout. can see size of seekbar represented thin blue frame in image above. frame has 2 small solid blue squares can grab mouse pointer resizing. if use mouse pointer drag little blue square match full width of frameview, let go of mouse, square pings original (too small) size.
what can fix this?.. if can achieve swipe unlock in fundamentally different way, i'm interested in too.
as promised see can do. have not used images , used android graphics drawing makes whole thing more customizable , and scalable. if insist in drawing images, use canvas.drawbitmap... it's pretty simple. main logic can stay same.
i may come , add fancy animations , visual effects, left commented out code play shaders , gradients bit short on time @ moment.
let's it... first crate attrs.xml in /resources/
, add it.
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="slidetounlock"> <attr name="slidercolor" format="color"/> <attr name="cancelonyexit" format="boolean"/> <attr name="slidetounlocktext" format="string"/> <attr name="slidetounlocktextcolor" format="color"/> <attr name="slidetounlockbackgroundcolor" format="color"/> <attr name="cornerradiusx" format="dimension"/> <attr name="cornerradiusy" format="dimension"/> </declare-styleable> </resources>
and slidetounlock.java
import android.annotation.suppresslint; import android.content.context; import android.content.res.resources; import android.content.res.typedarray; import android.graphics.canvas; import android.graphics.embossmaskfilter; import android.graphics.maskfilter; import android.graphics.paint; import android.graphics.path; import android.graphics.typeface; import android.os.build; import android.text.textutils; import android.util.attributeset; import android.view.motionevent; import android.view.view; /** * created ksenchy on 29.4.2015. */ public class slidetounlock extends view { public interface onslidetounlockeventlistener { public void onslidetounlockcanceled(); public void onslidetounlockdone(); } private int measuredwidth, measuredheight; private float density; private onslidetounlockeventlistener externallistener; private paint mbackgroundpaint, mtextpaint, msliderpaint; private float rx, ry; // corner radius private path mroundedrectpath; private string text = "unlock →"; float x; float event_x, event_y; float radius; float x_min, x_max; private boolean ignoretouchevents; // cancel when y coordinate leaves view? private boolean cancelonyexit; private boolean usedefaultcornerradiusx, usedefaultcornerradiusy; /** * default values * */ int backgroundcolor = 0xff807b7b; int textcolor = 0xffffffff; int slidercolor = 0xaa404040; public slidetounlock(context context) { super(context); init(context, null, 0); } public slidetounlock(context context, attributeset attrs) { super(context, attrs); init(context, attrs, 0); } public slidetounlock(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); init(context, attrs, defstyleattr); } public onslidetounlockeventlistener getexternallistener() { return externallistener; } public void setexternallistener(onslidetounlockeventlistener externallistener) { this.externallistener = externallistener; } private void init(context context, attributeset attrs, int style) { resources res = getresources(); density = res.getdisplaymetrics().density; typedarray = getcontext().obtainstyledattributes(attrs, r.styleable.slidetounlock, style, 0); string tmp = a.getstring(r.styleable.slidetounlock_slidetounlocktext); text = textutils.isempty(tmp) ? text : tmp; rx = a.getdimension(r.styleable.slidetounlock_cornerradiusx, rx); usedefaultcornerradiusx = rx == 0; ry = a.getdimension(r.styleable.slidetounlock_cornerradiusx, ry); usedefaultcornerradiusy = ry == 0; backgroundcolor = a.getcolor(r.styleable.slidetounlock_slidetounlockbackgroundcolor, backgroundcolor); textcolor = a.getcolor(r.styleable.slidetounlock_slidetounlocktextcolor, textcolor); slidercolor = a.getcolor(r.styleable.slidetounlock_slidercolor, slidercolor); cancelonyexit = a.getboolean(r.styleable.slidetounlock_cancelonyexit, false); a.recycle(); mroundedrectpath = new path(); mbackgroundpaint = new paint(paint.anti_alias_flag); mbackgroundpaint.setstyle(paint.style.fill); mbackgroundpaint.setcolor(backgroundcolor); mtextpaint = new paint(paint.anti_alias_flag); mtextpaint.setstyle(paint.style.fill); mtextpaint.setcolor(textcolor); mtextpaint.settypeface(typeface.create("roboto-thin", typeface.normal)); msliderpaint = new paint(paint.anti_alias_flag); msliderpaint.setstyle(paint.style.fill_and_stroke); msliderpaint.setcolor(slidercolor); msliderpaint.setstrokewidth(2 * density); if (!isineditmode()) { // edit mode not support shadow layers // msliderpaint.setshadowlayer(10.0f, 0.0f, 2.0f, 0xff000000); //msliderpaint.setmaskfilter(new embossmaskfilter(new float[]{1, 1, 1}, 0.4f, 10, 8.2f)); float[] direction = new float[]{0.0f, -1.0f, 0.5f}; maskfilter filter = new embossmaskfilter(direction, 0.8f, 15f, 1f); msliderpaint.setmaskfilter(filter); //msliderpaint.setshader(new lineargradient(8f, 80f, 30f, 20f, color.red,color.white, shader.tilemode.mirror)); //msliderpaint.setshader(new radialgradient(8f, 80f, 90f, color.red,color.white, shader.tilemode.mirror)); //msliderpaint.setshader(new sweepgradient(80, 80, color.red, color.white)); //msliderpaint.setmaskfilter(new blurmaskfilter(15, blurmaskfilter.blur.outer)); } } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { measuredheight = getdefaultsize(getsuggestedminimumheight(), heightmeasurespec); measuredwidth = getdefaultsize(getsuggestedminimumwidth(), widthmeasurespec); if (usedefaultcornerradiusx) { rx = measuredheight * 0.52f; } if (usedefaultcornerradiusy) { ry = measuredheight * 0.52f; } mtextpaint.settextsize(measuredheight / 3.0f); radius = measuredheight * 0.45f; x_min = 1.2f * radius; x_max = measuredwidth - x_min; x = x_min; setmeasureddimension(measuredwidth, measuredheight); } private void drawroundrect(canvas c) { mroundedrectpath.reset(); mroundedrectpath.moveto(rx, 0); mroundedrectpath.lineto(measuredwidth - rx, 0); mroundedrectpath.quadto(measuredwidth, 0, measuredwidth, ry); mroundedrectpath.lineto(measuredwidth, measuredheight - ry); mroundedrectpath.quadto(measuredwidth, measuredheight, measuredwidth - rx, measuredheight); mroundedrectpath.lineto(rx, measuredheight); mroundedrectpath.quadto(0, measuredheight, 0, measuredheight - ry); mroundedrectpath.lineto(0, ry); mroundedrectpath.quadto(0, 0, rx, 0); c.drawpath(mroundedrectpath, mbackgroundpaint); } @suppresslint("newapi") @override protected void ondraw(canvas canvas) { super.ondraw(canvas); if (measuredheight <= 0 || measuredwidth <= 0) { // there not can draw :/ return; } if (build.version.sdk_int >= 21) { canvas.drawroundrect(0, 0, measuredwidth, measuredheight, rx, ry, mbackgroundpaint); } else { drawroundrect(canvas); } // draw text in center float xpos = ((measuredwidth - mtextpaint.measuretext(text)) / 2.0f); float ypos = (measuredheight / 2.0f); float titleheight = math.abs(mtextpaint.descent() + mtextpaint.ascent()); ypos += titleheight / 2.0f; canvas.drawtext(text, xpos, ypos, mtextpaint); canvas.drawcircle(x, measuredheight * 0.5f, radius, msliderpaint); } private void oncancel() { reset(); if (externallistener != null) { externallistener.onslidetounlockcanceled(); } } private void onunlock() { if (externallistener != null) { externallistener.onslidetounlockdone(); } } private void reset() { x = x_min; invalidate(); } @override public boolean ontouchevent(motionevent event) { switch (event.getaction()) { case motionevent.action_up: ignoretouchevents = false; reset(); return true; case motionevent.action_down: // within circle?? event_x = event.getx(0); event_y = event.gety(0); double squareradius = radius * radius; double squaredxdistance = (event_x - x_min) * (event_x - x_min); double squaredydistance = (event_y - measuredheight / 2) * (event_y - measuredheight / 2); if (squaredxdistance + squaredydistance > squareradius) { // user touched outside button, ignore touch ignoretouchevents = true; } return true; case motionevent.action_cancel: ignoretouchevents = true; oncancel(); case motionevent.action_move: if (!ignoretouchevents) { event_x = event.getx(0); if (cancelonyexit) { event_y = event.gety(0); if (event_y < 0 || event_y > measuredheight) { ignoretouchevents = true; oncancel(); } } x = event_x > x_max ? x_max : event_x < x_min ? x_min : event_x; if (event_x >= x_max) { ignoretouchevents = true; onunlock(); } invalidate(); } return true; default: return super.ontouchevent(event); } } }
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ff000000"> <your.package.slidetounlock android:id="@+id/slidetounlock" android:layout_width="200dp" android:layout_height="50dp" android:layout_centerinparent="true"/> <your.package.slidetounlock android:id="@+id/slidetounlock2" android:layout_width="200dp" android:layout_height="50dp" android:layout_below="@+id/slidetounlock" android:layout_centerinparent="true" android:layout_margintop="50dp" app:cancelonyexit="true" app:slidetounlockbackgroundcolor="#808080" app:slidetounlocktext="slide unlock" app:slidetounlocktextcolor="#03a9f4" app:slidercolor="#aaffe97f"/> </relativelayout>
mainactivity.java
import android.os.bundle; import android.support.v7.app.actionbaractivity; import android.widget.toast; public class mainactivity extends actionbaractivity implements slidetounlock.onslidetounlockeventlistener { private slidetounlock slidetounlockview, slidetounlockview2; private toast toast; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); slidetounlockview = (slidetounlock) findviewbyid(r.id.slidetounlock); slidetounlockview.setexternallistener(this); slidetounlockview2 = (slidetounlock) findviewbyid(r.id.slidetounlock2); slidetounlockview2.setexternallistener(this); } private void showtoast(string text) { if (toast != null) { toast.cancel(); } toast = toast.maketext(this, text, toast.length_short); toast.show(); } @override public void onslidetounlockcanceled() { showtoast("canceled"); } @override public void onslidetounlockdone() { showtoast("unlocked"); } }
you can download whole project here. enjoy :)
this final result.
Comments
Post a Comment