欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-02-29 22:52:34
在andoird使用android自带的那些组件,像slidingdrawer和drawerlayout都是抽屉效果的菜单,但是在项目很多要实现的功能都收到android这...

在andoird使用android自带的那些组件,像slidingdrawer和drawerlayout都是抽屉效果的菜单,但是在项目很多要实现的功能都收到android这些自带组件的限制,导致很难完成项目的需求,自定义的组件,各方面都在自己的控制之下,从而根据需求做出调整。想要实现好的效果,基本上都的基于android的ontouch事件自己实现响应的功能。
首先,给大家先看一下整体的效果:

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

滑动的加速度效果都是有的,具体的体验,只能安装后才能查看。
接下来,看代码:
代码从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);
  }
 }
}

转载来自:

源码下载:抽屉效果

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