Android实现自定义滑动式抽屉效果菜单
程序员文章站
2024-02-29 22:52:34
在andoird使用android自带的那些组件,像slidingdrawer和drawerlayout都是抽屉效果的菜单,但是在项目很多要实现的功能都收到android这...
在andoird使用android自带的那些组件,像slidingdrawer和drawerlayout都是抽屉效果的菜单,但是在项目很多要实现的功能都收到android这些自带组件的限制,导致很难完成项目的需求,自定义的组件,各方面都在自己的控制之下,从而根据需求做出调整。想要实现好的效果,基本上都的基于android的ontouch事件自己实现响应的功能。
首先,给大家先看一下整体的效果:
滑动的加速度效果都是有的,具体的体验,只能安装后才能查看。
接下来,看代码:
代码从mainactivity延伸出了2个类:maincontroller和mainview,maincontroller来处理控制层、mainview来操作展示层。
主要代码:
mainactivity的代码:
package com.example.wz; import com.example.wz.controller.maincontroller; import com.example.wz.util.mylog; import com.example.wz.view.mainview; import android.app.activity; import android.os.bundle; import android.view.motionevent; public class mainactivity extends activity { public mylog log = new mylog(this, true); @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); log.e("欢迎你加入测试项目."); link(); } public maincontroller maincontroller; public mainview mainview; private void link() { this.maincontroller = new maincontroller(this); this.mainview = new mainview(this); this.maincontroller.thisview = this.mainview; this.mainview.thiscontroller = this.maincontroller; this.mainview.initviews(); } @override public boolean ontouchevent(motionevent event) { super.ontouchevent(event); return maincontroller.ontouchevent(event); } }
maincontroller的代码:
package com.example.wz.controller; import android.view.gesturedetector; import android.view.gesturedetector.simpleongesturelistener; import android.view.motionevent; import com.example.wz.mainactivity; import com.example.wz.util.mylog; import com.example.wz.util.openlooper; import com.example.wz.util.openlooper.loopcallback; import com.example.wz.view.mainview; public class maincontroller { public mylog log = new mylog(this, true); public mainactivity mainactivity; public maincontroller thiscontroller; public mainview thisview; public gesturedetector mgesture; public maincontroller(mainactivity mainactivity) { this.mainactivity = mainactivity; this.thiscontroller = this; mgesture = new gesturedetector(mainactivity, new gesturelistener()); openlooper = new openlooper(); openlooper.createopenlooper(); loopcallback = new listloopcallback(openlooper); openlooper.loopcallback = loopcallback; } public class touchstatus { public int none = 4, down = 1, horizontal = 2, vertical = 3, up = 4;// longpress = 5 public int state = none; } public touchstatus touchstatus = new touchstatus(); public class bodystatus { public int fixed = 0, dragging = 1, homing = 2, flinghoming = 3, boundaryhoming = 4; public int state = fixed; } public bodystatus bodystatus = new bodystatus(); public class drawstatus { public int closed = 0, open = 1, goclosing = 2, goopening = 3; public int state = closed; } public drawstatus drawstatus = new drawstatus(); public class areastatus { public int a = 0, b = 1; public int state = a; } public areastatus areastatus = new areastatus(); public float touch_pre_x; public float touch_pre_y; public float currenttranslatex; public boolean ontouchevent(motionevent event) { int action = event.getaction(); float x = event.getx(); float y = event.gety(); if (action == motionevent.action_down) { this.touch_pre_x = x; this.touch_pre_y = y; if (touchstatus.state == touchstatus.none) { touchstatus.state = touchstatus.down; log.e("down "); if (x > thisview.maxtranslatex) { areastatus.state = areastatus.b; } else if (x <= thisview.maxtranslatex) { areastatus.state = areastatus.a; } } } else if (action == motionevent.action_move) { float δy = (y - touch_pre_y); float δx = (x - touch_pre_x); if (touchstatus.state == touchstatus.down) { if (δx * δx + δy * δy > 400) { if (δx * δx > δy * δy) { touchstatus.state = touchstatus.horizontal; } else { touchstatus.state = touchstatus.vertical; } touch_pre_x = x; touch_pre_y = y; log.e("action_move "); } } else if (touchstatus.state == touchstatus.horizontal) { currenttranslatex += δx; this.touch_pre_x = x; this.touch_pre_y = y; if (currenttranslatex - thisview.maxtranslatex <= 0 && currenttranslatex >= 0) { setposition(); } log.e("horizontal"); bodystatus.state = bodystatus.dragging; } else if (touchstatus.state == touchstatus.vertical) { log.e("vertical"); bodystatus.state = bodystatus.dragging; } } else if (action == motionevent.action_up) { log.e("action_up"); if (bodystatus.state == bodystatus.dragging) { if (touchstatus.state == touchstatus.horizontal) { bodystatus.state = bodystatus.homing; openlooper.start(); } else if (touchstatus.state == touchstatus.vertical) { if (drawstatus.state == drawstatus.open && areastatus.state == areastatus.b) { bodystatus.state = bodystatus.homing; drawstatus.state = drawstatus.goclosing; openlooper.start(); } } } else if (touchstatus.state == touchstatus.down && areastatus.state == areastatus.b) { bodystatus.state = bodystatus.homing; drawstatus.state = drawstatus.goclosing; openlooper.start(); } touchstatus.state = touchstatus.up; } mgesture.ontouchevent(event); return true; } class gesturelistener extends simpleongesturelistener { @override public boolean onfling(motionevent e1, motionevent e2, float velocityx, float velocityy) { if (velocityx * velocityx + velocityy * velocityy > 250000) { if (velocityx * velocityx > velocityy * velocityy) { log.e("velocityx--" + velocityx); if (drawstatus.state == drawstatus.closed && velocityx < 0) { } else if (drawstatus.state == drawstatus.open && velocityx > 0) { } else { dxspeed = velocityx; bodystatus.state = bodystatus.flinghoming; openlooper.start(); } } else { log.e("velocityy"); } } return true; } public void onlongpress(motionevent event) { } public boolean ondoubletap(motionevent event) { return false; } public boolean ondoubletapevent(motionevent event) { return false; } public boolean onsingletapup(motionevent event) { return false; } @override public boolean onsingletapconfirmed(motionevent event) { return false; } public boolean onscroll(motionevent e1, motionevent e2, float distancex, float distancey) { return false; } } public void setposition() { thisview.v1.settranslationx(currenttranslatex - thisview.maxtranslatex); thisview.v2.settranslationx(math.abs(currenttranslatex)); } float transletespeed = 3f; openlooper openlooper = null; loopcallback loopcallback = null; public class listloopcallback extends loopcallback { public listloopcallback(openlooper openlooper) { openlooper.super(); } @override public void loop(double ellapsedmillis) { if (bodystatus.state == bodystatus.homing) { hommingview((float) ellapsedmillis); } else if (bodystatus.state == bodystatus.flinghoming) { flinghomingview((float) ellapsedmillis); } } } public float ratio = 0.0008f; public void flinghomingview(float ellapsedmillis) { float distance = (float) ellapsedmillis * transletespeed; boolean isstop = false; if (drawstatus.state == drawstatus.closed) { drawstatus.state = drawstatus.goopening; } else if (drawstatus.state == drawstatus.open) { drawstatus.state = drawstatus.goclosing; } if (drawstatus.state == drawstatus.goclosing) { this.currenttranslatex -= distance; if (this.currenttranslatex <= 0) { this.currenttranslatex = 0; drawstatus.state = drawstatus.closed; isstop = true; log.e("-------------1"); } } else if (drawstatus.state == drawstatus.goopening) { this.currenttranslatex += distance; if (this.currenttranslatex >= thisview.maxtranslatex) { this.currenttranslatex = thisview.maxtranslatex; drawstatus.state = drawstatus.open; isstop = true; log.e("-------------2"); } } setposition(); if (isstop) { openlooper.stop(); } } public float dxspeed; public void dampenspeed(long deltamillis) { if (this.dxspeed != 0.0f) { this.dxspeed *= (1.0f - 0.002f * deltamillis); if (math.abs(this.dxspeed) < 50f) this.dxspeed = 0.0f; } } public void hommingview(float ellapsedmillis) { float distance = (float) ellapsedmillis * transletespeed; boolean isstop = false; if (drawstatus.state == drawstatus.closed && this.currenttranslatex < thisview.maxtranslatex / 5) { this.currenttranslatex -= distance; if (this.currenttranslatex <= 0) { this.currenttranslatex = 0; drawstatus.state = drawstatus.closed; isstop = true; } } else if (drawstatus.state == drawstatus.closed && this.currenttranslatex >= thisview.maxtranslatex / 5) { this.currenttranslatex += distance; if (this.currenttranslatex >= thisview.maxtranslatex) { this.currenttranslatex = thisview.maxtranslatex; drawstatus.state = drawstatus.open; isstop = true; } } else if (drawstatus.state == drawstatus.open && this.currenttranslatex < thisview.maxtranslatex / 5 * 4) { this.currenttranslatex -= distance; if (this.currenttranslatex <= 0) { this.currenttranslatex = 0; drawstatus.state = drawstatus.closed; isstop = true; } } else if (drawstatus.state == drawstatus.open && this.currenttranslatex >= thisview.maxtranslatex / 5 * 4) { this.currenttranslatex += distance; if (this.currenttranslatex >= thisview.maxtranslatex) { this.currenttranslatex = thisview.maxtranslatex; drawstatus.state = drawstatus.open; isstop = true; } } else if (drawstatus.state == drawstatus.goclosing) { this.currenttranslatex -= distance; if (this.currenttranslatex <= 0) { this.currenttranslatex = 0; drawstatus.state = drawstatus.closed; isstop = true; } } setposition(); if (isstop) { openlooper.stop(); log.e("looper stop..."); } } }
mainview的代码:
package com.example.wz.view; import android.graphics.color; import android.util.displaymetrics; import android.view.viewgroup.layoutparams; import android.widget.relativelayout; import android.widget.textview; import com.example.wz.mainactivity; import com.example.wz.r; import com.example.wz.controller.maincontroller; import com.example.wz.util.mylog; public class mainview { public mylog log = new mylog(this, true); public mainactivity mainactivity; public maincontroller thiscontroller; public mainview thisview; public mainview(mainactivity mainactivity) { this.mainactivity = mainactivity; this.thisview = this; } public displaymetrics displaymetrics; public float screenwidth; public float screenheight; public float density; public float maxtranslatex; public relativelayout maxview; public relativelayout v1; public relativelayout v2; public void initviews() { this.displaymetrics = new displaymetrics(); this.mainactivity.getwindowmanager().getdefaultdisplay().getmetrics(this.displaymetrics); this.screenheight = this.displaymetrics.heightpixels; this.screenwidth = this.displaymetrics.widthpixels; this.density = this.displaymetrics.density; this.maxtranslatex = this.screenwidth * 0.8f; this.mainactivity.setcontentview(r.layout.activity_main); this.maxview = (relativelayout) this.mainactivity.findviewbyid(r.id.maxview); v1 = new relativelayout(mainactivity); v1.setbackgroundcolor(color.red); relativelayout.layoutparams params1 = new relativelayout.layoutparams((int) this.maxtranslatex, layoutparams.match_parent); this.maxview.addview(v1, params1); textview t1 = new textview(mainactivity); t1.settext("left menu bar"); t1.settextcolor(color.white); v1.addview(t1); v1.settranslationx(0 - this.maxtranslatex); v2 = new relativelayout(mainactivity); v2.setbackgroundcolor(color.parsecolor("#0099cd")); relativelayout.layoutparams params2 = new relativelayout.layoutparams((int) this.screenwidth, layoutparams.match_parent); this.maxview.addview(v2, params2); v2.settranslationx(0); textview t2 = new textview(mainactivity); t2.settext("body content"); t2.settextcolor(color.white); v2.addview(t2); } }
日志管理类mylog:
package com.example.wz.util; import android.util.log; public class mylog { public static boolean isglobalturnon = true; public boolean isturnon = true; public string tag = null; public mylog(string tag, boolean isturnon) { this.tag = tag; this.isturnon = isturnon; } public mylog(object clazz, boolean isturnon) { this.tag = clazz.getclass().getsimplename(); this.isturnon = isturnon; } public void v(string message) { this.v(this.tag, message); } public void d(string message) { this.d(this.tag, message); } public void i(string message) { this.i(this.tag, message); } public void w(string message) { this.w(this.tag, message); } public void e(string message) { this.e(this.tag, message); } public void v(string tag, string message) { if (isturnon && isglobalturnon) { log.v(tag, message); } } public void d(string tag, string message) { if (isturnon && isglobalturnon) { log.d(tag, message); } } public void i(string tag, string message) { if (isturnon && isglobalturnon) { log.i(tag, message); } } public void w(string tag, string message) { if (isturnon && isglobalturnon) { log.w(tag, message); } } public void e(string tag, string message) { if (isturnon && isglobalturnon) { log.e(tag, message); } } }
实现动画效果的核心类openlooper:
package com.example.wz.util; import android.annotation.targetapi; import android.os.build; import android.os.handler; import android.os.systemclock; import android.view.choreographer; public class openlooper { public legacyandroidspringlooper legacyandroidspringlooper = null; public choreographerandroidspringlooper choreographerandroidspringlooper = null; public loopcallback loopcallback = null; public void createopenlooper() { if (build.version.sdk_int >= build.version_codes.jelly_bean) { choreographerandroidspringlooper = new choreographerandroidspringlooper(); } else { legacyandroidspringlooper = new legacyandroidspringlooper(); } } public void start() { if (choreographerandroidspringlooper != null) { choreographerandroidspringlooper.start(); } else if (legacyandroidspringlooper != null) { legacyandroidspringlooper.start(); } } public void stop() { if (choreographerandroidspringlooper != null) { choreographerandroidspringlooper.stop(); } else if (legacyandroidspringlooper != null) { legacyandroidspringlooper.stop(); } } public class loopcallback { public void loop(double ellapsedmillis) { } } public void loop(double ellapsedmillis) { if (this.loopcallback != null) { this.loopcallback.loop(ellapsedmillis); } } public class legacyandroidspringlooper { public handler mhandler; public runnable mlooperrunnable; public boolean mstarted; public long mlasttime; public legacyandroidspringlooper() { initialize(new handler()); } public void initialize(handler handler) { mhandler = handler; mlooperrunnable = new runnable() { @override public void run() { if (!mstarted) { return; } long currenttime = systemclock.uptimemillis(); loop(currenttime - mlasttime); mhandler.post(mlooperrunnable); } }; } public void start() { if (mstarted) { return; } mstarted = true; mlasttime = systemclock.uptimemillis(); mhandler.removecallbacks(mlooperrunnable); mhandler.post(mlooperrunnable); } public void stop() { mstarted = false; mhandler.removecallbacks(mlooperrunnable); } } @targetapi(build.version_codes.jelly_bean) public class choreographerandroidspringlooper { public choreographer mchoreographer; public choreographer.framecallback mframecallback; public boolean mstarted; public long mlasttime; public choreographerandroidspringlooper() { initialize(choreographer.getinstance()); } public void initialize(choreographer choreographer) { mchoreographer = choreographer; mframecallback = new choreographer.framecallback() { @override public void doframe(long frametimenanos) { if (!mstarted) { return; } long currenttime = systemclock.uptimemillis(); loop(currenttime - mlasttime); mlasttime = currenttime; mchoreographer.postframecallback(mframecallback); } }; } public void start() { if (mstarted) { return; } mstarted = true; mlasttime = systemclock.uptimemillis(); mchoreographer.removeframecallback(mframecallback); mchoreographer.postframecallback(mframecallback); } public void stop() { mstarted = false; mchoreographer.removeframecallback(mframecallback); } } }
转载来自:
源码下载:抽屉效果
以上就是本文的全部内容,希望对大家的学习有所帮助。
下一篇: Java基础教程之实现接口