当前位置: 移动技术网 > 移动技术>移动开发>Android > Android实现自定义滑动式抽屉效果菜单

Android实现自定义滑动式抽屉效果菜单

2019年07月24日  | 移动技术网移动技术  | 我要评论

在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);
  }
 }
}

转载来自:

源码下载:

以上就是本文的全部内容,希望对大家的学习有所帮助。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网