Android开源AndroidSideMenu实现抽屉和侧滑菜单

AndroidSideMenu能够让你轻而易举地创建侧滑菜单。需要注意的是,该项目自身并不提供任何创建菜单的工具,因此,开发者可以自由创建内部菜单。

核心类如下:

/*
 * Copyright dmitry.zaicew@gmail.com Dmitry Zaitsev
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

package com.agimind.widget; 

import java.util.LinkedList;
import java.util.Queue; 

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.Region.Op;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Transformation;
import android.widget.FrameLayout; 

public class SlideHolder extends FrameLayout { 

  public final static int DIRECTION_LEFT = 1;
  public final static int DIRECTION_RIGHT = -1; 

  protected final static int MODE_READY = 0;
  protected final static int MODE_SLIDE = 1;
  protected final static int MODE_FINISHED = 2; 

  private Bitmap mCachedBitmap;
  private Canvas mCachedCanvas;
  private Paint mCachedPaint;
  private View mMenuView; 

  private int mMode = MODE_READY;
  private int mDirection = DIRECTION_LEFT; 

  private int mOffset = 0;
  private int mStartOffset;
  private int mEndOffset; 

  private boolean mEnabled = true;
  private boolean mInterceptTouch = true;
  private boolean mAlwaysOpened = false;
  private boolean mDispatchWhenOpened = false; 

  private Queue<Runnable> mWhenReady = new LinkedList<Runnable>(); 

  private OnSlideListener mListener; 

  public SlideHolder(Context context) {
    super(context); 

    initView();
  } 

  public SlideHolder(Context context, AttributeSet attrs) {
    super(context, attrs); 

    initView();
  } 

  public SlideHolder(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle); 

    initView();
  } 

  private void initView() {
    mCachedPaint = new Paint(
          Paint.ANTI_ALIAS_FLAG
          | Paint.FILTER_BITMAP_FLAG
          | Paint.DITHER_FLAG
        );
  } 

  @Override
  public void setEnabled(boolean enabled) {
    mEnabled = enabled;
  } 

  @Override
  public boolean isEnabled() {
    return mEnabled;
  } 

  /**
   *
   * @param direction - direction in which SlideHolder opens. Can be: DIRECTION_LEFT, DIRECTION_RIGHT
   */
  public void setDirection(int direction) {
    closeImmediately(); 

    mDirection = direction;
  } 

  /**
   *
   * @param allow - if false, SlideHolder won't react to swiping gestures (but still will be able to work by manually invoking mathods)
   */
  public void setAllowInterceptTouch(boolean allow) {
    mInterceptTouch = allow;
  } 

  public boolean isAllowedInterceptTouch() {
    return mInterceptTouch;
  } 

  /**
   *
   * @param dispatch - if true, in open state SlideHolder will dispatch touch events to main layout (in other words - it will be clickable)
   */
  public void setDispatchTouchWhenOpened(boolean dispatch) {
    mDispatchWhenOpened = dispatch;
  } 

  public boolean isDispatchTouchWhenOpened() {
    return mDispatchWhenOpened;
  } 

  /**
   *
   * @param opened - if true, SlideHolder will always be in opened state (which means that swiping won't work)
   */
  public void setAlwaysOpened(boolean opened) {
    mAlwaysOpened = opened; 

    requestLayout();
  } 

  public int getMenuOffset() {
    return mOffset;
  } 

  public void setOnSlideListener(OnSlideListener lis) {
    mListener = lis;
  } 

  public boolean isOpened() {
    return mAlwaysOpened || mMode == MODE_FINISHED;
  } 

  public void toggle(boolean immediately) {
    if(immediately) {
      toggleImmediately();
    } else {
      toggle();
    }
  } 

  public void toggle() {
    if(isOpened()) {
      close();
    } else {
      open();
    }
  } 

  public void toggleImmediately() {
    if(isOpened()) {
      closeImmediately();
    } else {
      openImmediately();
    }
  } 

  public boolean open() {
    if(isOpened() || mAlwaysOpened || mMode == MODE_SLIDE) {
      return false;
    } 

    if(!isReadyForSlide()) {
      mWhenReady.add(new Runnable() { 

        @Override
        public void run() {
          open();
        }
      }); 

      return true;
    } 

    initSlideMode(); 

    Animation anim = new SlideAnimation(mOffset, mEndOffset);
    anim.setAnimationListener(mOpenListener);
    startAnimation(anim); 

    invalidate(); 

    return true;
  } 

  public boolean openImmediately() {
    if(isOpened() || mAlwaysOpened || mMode == MODE_SLIDE) {
      return false;
    } 

    if(!isReadyForSlide()) {
      mWhenReady.add(new Runnable() { 

        @Override
        public void run() {
          openImmediately();
        }
      }); 

      return true;
    } 

    mMenuView.setVisibility(View.VISIBLE);
    mMode = MODE_FINISHED;
    requestLayout(); 

    if(mListener != null) {
      mListener.onSlideCompleted(true);
    } 

    return true;
  } 

  public boolean close() {
    if(!isOpened() || mAlwaysOpened || mMode == MODE_SLIDE) {
      return false;
    } 

    if(!isReadyForSlide()) {
      mWhenReady.add(new Runnable() { 

        @Override
        public void run() {
          close();
        }
      }); 

      return true;
    } 

    initSlideMode(); 

    Animation anim = new SlideAnimation(mOffset, mEndOffset);
    anim.setAnimationListener(mCloseListener);
    startAnimation(anim); 

    invalidate(); 

    return true;
  } 

  public boolean closeImmediately() {
    if(!isOpened() || mAlwaysOpened || mMode == MODE_SLIDE) {
      return false;
    } 

    if(!isReadyForSlide()) {
      mWhenReady.add(new Runnable() { 

        @Override
        public void run() {
          closeImmediately();
        }
      }); 

      return true;
    } 

    mMenuView.setVisibility(View.GONE);
    mMode = MODE_READY;
    requestLayout(); 

    if(mListener != null) {
      mListener.onSlideCompleted(false);
    } 

    return true;
  } 

  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    final int parentLeft = 0;
    final int parentTop = 0;
    final int parentRight = r - l;
    final int parentBottom = b - t; 

    View menu = getChildAt(0);
    int menuWidth = menu.getMeasuredWidth(); 

    if(mDirection == DIRECTION_LEFT) {
      menu.layout(parentLeft, parentTop, parentLeft+menuWidth, parentBottom);
    } else {
      menu.layout(parentRight-menuWidth, parentTop, parentRight, parentBottom);
    } 

    if(mAlwaysOpened) {
      if(mDirection == DIRECTION_LEFT) {
        mOffset = menuWidth;
      } else {
        mOffset = 0;
      }
    } else if(mMode == MODE_FINISHED) {
      mOffset = mDirection*menuWidth;
    } else if(mMode == MODE_READY) {
      mOffset = 0;
    } 

    View main = getChildAt(1);
    main.layout(
          parentLeft + mOffset,
          parentTop,
          parentLeft + mOffset + main.getMeasuredWidth(),
          parentBottom
        ); 

    invalidate(); 

    Runnable rn;
    while((rn = mWhenReady.poll()) != null) {
      rn.run();
    }
  } 

  private boolean isReadyForSlide() {
    return (getWidth() > 0 && getHeight() > 0);
  } 

  @Override
  protected void onMeasure(int wSp, int hSp) {
    mMenuView = getChildAt(0); 

    if(mAlwaysOpened) {
      View main = getChildAt(1); 

      if(mMenuView != null && main != null) {
        measureChild(mMenuView, wSp, hSp);
        LayoutParams lp = (LayoutParams) main.getLayoutParams(); 

        if(mDirection == DIRECTION_LEFT) {
          lp.leftMargin = mMenuView.getMeasuredWidth();
        } else {
          lp.rightMargin = mMenuView.getMeasuredWidth();
        }
      }
    } 

    super.onMeasure(wSp, hSp);
  } 

  private byte mFrame = 0; 

  @Override
  protected void dispatchDraw(Canvas canvas) {
    try {
      if(mMode == MODE_SLIDE) {
        View main = getChildAt(1);
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
          /*
           * On new versions we redrawing main layout only
           * if it's marked as dirty
           */
          if(main.isDirty()) {
            mCachedCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
            main.draw(mCachedCanvas);
        }
        } else {
          /*
           * On older versions we just redrawing our cache
           * every 5th frame
           */
          if(++mFrame % 5 == 0) {
            mCachedCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
            main.draw(mCachedCanvas);
          }
        } 

        /*
         * Draw only visible part of menu
         */ 

        View menu = getChildAt(0);
        final int scrollX = menu.getScrollX();
        final int scrollY = menu.getScrollY(); 

        canvas.save(); 

        if(mDirection == DIRECTION_LEFT) {
          canvas.clipRect(0, 0, mOffset, menu.getHeight(), Op.REPLACE);
        } else {
          int menuWidth = menu.getWidth();
          int menuLeft = menu.getLeft(); 

          canvas.clipRect(menuLeft+menuWidth+mOffset, 0, menuLeft+menuWidth, menu.getHeight());
        } 

        canvas.translate(menu.getLeft(), menu.getTop());
        canvas.translate(-scrollX, -scrollY); 

        menu.draw(canvas); 

        canvas.restore(); 

        canvas.drawBitmap(mCachedBitmap, mOffset, 0, mCachedPaint);
      } else {
        if(!mAlwaysOpened && mMode == MODE_READY) {
          mMenuView.setVisibility(View.GONE);
        } 

        super.dispatchDraw(canvas);
      }
    } catch(IndexOutOfBoundsException e) {
      /*
       * Possibility of crashes on some devices (especially on Samsung).
       * Usually, when ListView is empty.
       */
    }
  } 

  private int mHistoricalX = 0;
  private boolean mCloseOnRelease = false; 

  @Override
  public boolean dispatchTouchEvent(MotionEvent ev) {
    if(((!mEnabled || !mInterceptTouch) && mMode == MODE_READY) || mAlwaysOpened) {
      return super.dispatchTouchEvent(ev);
    } 

    if(mMode != MODE_FINISHED) {
      onTouchEvent(ev); 

      if(mMode != MODE_SLIDE) {
        super.dispatchTouchEvent(ev);
      } else {
        MotionEvent cancelEvent = MotionEvent.obtain(ev);
        cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
        super.dispatchTouchEvent(cancelEvent);
        cancelEvent.recycle();
      } 

      return true;
    } else {
      final int action = ev.getAction(); 

      Rect rect = new Rect();
      View menu = getChildAt(0);
      menu.getHitRect(rect); 

      if(!rect.contains((int) ev.getX(), (int) ev.getY())) {
        if (action == MotionEvent.ACTION_UP && mCloseOnRelease && !mDispatchWhenOpened) {
          close();
          mCloseOnRelease = false;
        } else {
          if(action == MotionEvent.ACTION_DOWN && !mDispatchWhenOpened) {
            mCloseOnRelease = true;
          } 

          onTouchEvent(ev);
        } 

        if(mDispatchWhenOpened) {
          super.dispatchTouchEvent(ev);
        } 

        return true;
      } else {
        onTouchEvent(ev); 

        ev.offsetLocation(-menu.getLeft(), -menu.getTop());
        menu.dispatchTouchEvent(ev); 

        return true;
      }
    }
  } 

  private boolean handleTouchEvent(MotionEvent ev) {
    if(!mEnabled) {
      return false;
    } 

    float x = ev.getX(); 

    if(ev.getAction() == MotionEvent.ACTION_DOWN) {
      mHistoricalX = (int) x; 

      return true;
    } 

    if(ev.getAction() == MotionEvent.ACTION_MOVE) { 

      float diff = x - mHistoricalX; 

      if((mDirection*diff > 50 && mMode == MODE_READY) || (mDirection*diff < -50 && mMode == MODE_FINISHED)) {
        mHistoricalX = (int) x; 

        initSlideMode();
      } else if(mMode == MODE_SLIDE) {
        mOffset += diff; 

        mHistoricalX = (int) x; 

        if(!isSlideAllowed()) {
          finishSlide();
        }
      } else {
        return false;
      }
    } 

    if(ev.getAction() == MotionEvent.ACTION_UP) {
      if(mMode == MODE_SLIDE) {
        finishSlide();
      } 

      mCloseOnRelease = false; 

      return false;
    } 

    return mMode == MODE_SLIDE;
  } 

  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    boolean handled = handleTouchEvent(ev); 

    invalidate(); 

    return handled;
  } 

  private void initSlideMode() {
    mCloseOnRelease = false; 

    View v = getChildAt(1); 

    if(mMode == MODE_READY) {
      mStartOffset = 0;
      mEndOffset = mDirection*getChildAt(0).getWidth();
    } else {
      mStartOffset = mDirection*getChildAt(0).getWidth();
      mEndOffset = 0;
    } 

    mOffset = mStartOffset; 

    if(mCachedBitmap == null || mCachedBitmap.isRecycled() || mCachedBitmap.getWidth() != v.getWidth()) {
      mCachedBitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
      mCachedCanvas = new Canvas(mCachedBitmap);
    } else {
      mCachedCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
    } 

    v.setVisibility(View.VISIBLE); 

    mCachedCanvas.translate(-v.getScrollX(), -v.getScrollY());
    v.draw(mCachedCanvas); 

    mMode = MODE_SLIDE; 

    mMenuView.setVisibility(View.VISIBLE);
  } 

  private boolean isSlideAllowed() {
    return (mDirection*mEndOffset > 0 && mDirection*mOffset < mDirection*mEndOffset && mDirection*mOffset >= mDirection*mStartOffset)
        || (mEndOffset == 0 && mDirection*mOffset > mDirection*mEndOffset && mDirection*mOffset <= mDirection*mStartOffset);
  } 

  private void completeOpening() {
    mOffset = mDirection*mMenuView.getWidth();
    requestLayout(); 

    post(new Runnable() { 

      @Override
      public void run() {
        mMode = MODE_FINISHED;
        mMenuView.setVisibility(View.VISIBLE);
      }
    }); 

    if(mListener != null) {
      mListener.onSlideCompleted(true);
    }
  } 

  private Animation.AnimationListener mOpenListener = new Animation.AnimationListener() { 

    @Override
    public void onAnimationStart(Animation animation) {} 

    @Override
    public void onAnimationRepeat(Animation animation) {} 

    @Override
    public void onAnimationEnd(Animation animation) {
      completeOpening();
    }
  }; 

  private void completeClosing() {
    mOffset = 0;
    requestLayout(); 

    post(new Runnable() { 

      @Override
      public void run() {
        mMode = MODE_READY;
        mMenuView.setVisibility(View.GONE);
      }
    }); 

    if(mListener != null) {
      mListener.onSlideCompleted(false);
    }
  } 

  private Animation.AnimationListener mCloseListener = new Animation.AnimationListener() { 

    @Override
    public void onAnimationStart(Animation animation) {} 

    @Override
    public void onAnimationRepeat(Animation animation) {} 

    @Override
    public void onAnimationEnd(Animation animation) {
      completeClosing();
    }
  }; 

  private void finishSlide() {
    if(mDirection*mEndOffset > 0) {
      if(mDirection*mOffset > mDirection*mEndOffset/2) {
        if(mDirection*mOffset > mDirection*mEndOffset) mOffset = mEndOffset; 

        Animation anim = new SlideAnimation(mOffset, mEndOffset);
        anim.setAnimationListener(mOpenListener);
        startAnimation(anim);
      } else {
        if(mDirection*mOffset < mDirection*mStartOffset) mOffset = mStartOffset; 

        Animation anim = new SlideAnimation(mOffset, mStartOffset);
        anim.setAnimationListener(mCloseListener);
        startAnimation(anim);
      }
    } else {
      if(mDirection*mOffset < mDirection*mStartOffset/2) {
        if(mDirection*mOffset < mDirection*mEndOffset) mOffset = mEndOffset; 

        Animation anim = new SlideAnimation(mOffset, mEndOffset);
        anim.setAnimationListener(mCloseListener);
        startAnimation(anim);
      } else {
        if(mDirection*mOffset > mDirection*mStartOffset) mOffset = mStartOffset; 

        Animation anim = new SlideAnimation(mOffset, mStartOffset);
        anim.setAnimationListener(mOpenListener);
        startAnimation(anim);
      }
    }
  } 

  private class SlideAnimation extends Animation { 

    private static final float SPEED = 0.6f; 

    private float mStart;
    private float mEnd; 

    public SlideAnimation(float fromX, float toX) {
      mStart = fromX;
      mEnd = toX; 

      setInterpolator(new DecelerateInterpolator()); 

      float duration = Math.abs(mEnd - mStart) / SPEED;
      setDuration((long) duration);
    } 

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
      super.applyTransformation(interpolatedTime, t); 

      float offset = (mEnd - mStart) * interpolatedTime + mStart;
      mOffset = (int) offset; 

      postInvalidate();
    } 

  } 

  public static interface OnSlideListener {
    public void onSlideCompleted(boolean opened);
  } 

} 

使用:

package com.agimind.sidemenuexample; 

import com.agimind.widget.SlideHolder; 

import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.app.ActionBar;
import android.app.Activity; 

public class MainActivity extends Activity { 

  private SlideHolder mSlideHolder; 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main); 

    mSlideHolder = (SlideHolder) findViewById(R.id.slideHolder);
    // mSlideHolder.setAllowInterceptTouch(false);
    // mSlideHolder.setAlwaysOpened(true);
    /*
     * toggleView can actually be any view you want. Here, for simplicity,
     * we're using TextView, but you can easily replace it with button.
     *
     * Note, when menu opens our textView will become invisible, so it quite
     * pointless to assign toggle-event to it. In real app consider using UP
     * button instead. In our case toggle() can be replaced with open().
     */ 

    ActionBar actionBar = getActionBar();
    actionBar.setDisplayShowHomeEnabled(true);
    actionBar.setHomeButtonEnabled(true); 

    View toggleView = findViewById(R.id.textView);
    toggleView.setOnClickListener(new View.OnClickListener() { 

      @Override
      public void onClick(View v) {
        mSlideHolder.toggle();
      }
    });
  } 

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case android.R.id.home:
      mSlideHolder.toggle();
      break; 

    default:
      break;
    }
    return super.onOptionsItemSelected(item);
  }
}

布局如下:

<com.agimind.widget.SlideHolder xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/slideHolder"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  tools:context=".MainActivity" > 

  <ScrollView
    android:layout_width="200dp"
    android:layout_height="fill_parent"
    android:background="@android:color/black" > 

    <LinearLayout
      android:layout_width="200dp"
      android:layout_height="wrap_content"
      android:orientation="vertical" > 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" /> 

      <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/menu_settings" />
    </LinearLayout>
  </ScrollView> 

  <RelativeLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" > 

    <TextView
      android:id="@+id/textView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerHorizontal="true"
      android:layout_centerVertical="true"
      android:text="@string/swipe"
      android:textSize="25sp" /> 

  </RelativeLayout> 

</com.agimind.widget.SlideHolder>

下载:AndroidSideMenu

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

(0)

相关推荐

  • Android App中DrawerLayout抽屉效果的菜单编写实例

    抽屉效果的导航菜单 看了很多应用,觉得这种侧滑的抽屉效果的菜单很好. 不用切换到另一个页面,也不用去按菜单的硬件按钮,直接在界面上一个按钮点击,菜单就滑出来,而且感觉能放很多东西. 库的引用: 首先, DrawerLayout这个类是在Support Library里的,需要加上android-support-v4.jar这个包. 然后程序中用时在前面导入import android.support.v4.widget.DrawerLayout; 如果找不到这个类,首先用SDK Manager更

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

    在Andoird使用Android自带的那些组件,像SlidingDrawer和DrawerLayout都是抽屉效果的菜单,但是在项目很多要实现的功能都收到Android这些自带组件的限制,导致很难完成项目的需求,自定义的组件,各方面都在自己的控制之下,从而根据需求做出调整.想要实现好的效果,基本上都的基于Android的OnTouch事件自己实现响应的功能. 首先,给大家先看一下整体的效果: 滑动的加速度效果都是有的,具体的体验,只能安装后才能查看. 接下来,看代码: 代码从MainActiv

  • Android控件之SlidingDrawer(滑动式抽屉)详解与实例分享

    SlidingDrawer效果想必大家也见到过,它就是1.5模拟器上进入应用程序列表的效果.下面是截图 一.简介  SlidingDrawer隐藏屏外的内容,并允许用户通过handle以显示隐藏内容.它可以垂直或水平滑动,它有俩个View组成,其一 是可以拖动的handle,其二是隐藏内容的View.它里面的控件必须设置布局,在布局文件中必须指定handle和content.例如下面 复制代码 代码如下: <SlidingDrawer android:layout_width="fill_

  • Android自定义控件仿QQ抽屉效果

    其实网上类似的实现已经很多了,原理也并不难,只是网上各种demo运行下来,多少都有一些问题.折腾了半天,决定自己实现一个. 首先我们看看实现效果: 对比网上各类demo,这次要实现的主要表现在以下几点: 1.侧滑显示抽屉view 2.侧滑抽屉隐藏view控件点击事件 3.单击任意item隐藏显示的抽屉view 4.滑动list隐藏显示的抽屉view 5.增加SwipeLayout点击事件和Swipe touch事件判断处理 6.优化快速划开多个抽屉隐藏view时多个SwipeLayout滑动状态

  • Android组件之DrawerLayout实现抽屉菜单

    DrawerLayout组件同样是V4包中的组件,也是直接继承于ViewGroup类,所以这个类也是一个容器类. 抽屉菜单的摆放和布局通过android:layout_gravity属性来控制,可选值为left.right或start.end.通过xml来布局的话,需要把DrawerLayout作为父容器,组界面布局作为其第一个子节点,抽屉布局则紧随其后作为第二个子节点,这样就做就已经把内容展示区和抽屉菜单区独立开来,只需要分别为两个区域设置内容即可.android提供了一些实用的监听器,重载相

  • Android实现右边抽屉Drawerlayout效果

    侧边栏是Android应用中很常见的一个界面效果(抽屉效果).而利用DrawerLayout实现右侧栏是相对简单的.而且这个控件自带滑动效果,十分方便. DrawerLayout属于android-support-v4.jar的包的内容,sdk新的就不用更新了,如果旧版本就需要导入这个包了. 先来看看效果 这里实现了抽屉效果和为了方便使用者在各处可以随意打开这个抽屉,我在这里定义在点击菜单可出现抽屉. 代码说明 1.activity的布局文件 <android.support.v4.widget

  • Android抽屉导航Navigation Drawer实例解析

    我们重点来研究一下Android抽屉导航 NavigationDrawer.先来感性认识一下这种效果吧: 看了很多应用,觉得这种侧滑的抽屉效果的菜单很好.不用切换到另一个页面,也不用去按菜单的硬件按钮,直接在界面上一个按钮点击,菜单就滑出来,而且感觉能放很多东西. 最简单就是用官方的抽屉导航 NavigationDrawerLayout 来实现.DrawerLayout这个类是在Support Library里的,需要加上android-support-v4.jar这个包.然后程序中用时在前面导

  • Android DrawerLayout实现抽屉效果实例代码

    官网:https://developer.android.com/training/implementing-navigation/nav-drawer.html 贴上主要的逻辑和布局文件: activity_main.xml <?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schema

  • Android提高之多方向抽屉实现方法

    说起在android上要实现类似Launch的抽屉效果,大家一定首先会想起SlidingDrawer.SlidingDrawer是android官方控件之一,但是本文的主角并不是它,而是民间的控件工具集合:android-misc-widgets.android-misc-widgets里面包含几个widget:Panel.SmoothButton.Switcher.VirtualKeyboard,还有一些动画特效,本文主要介绍抽屉容器Panel的用法.android-misc-widgets的

  • Android 抽屉效果的导航菜单实现代码实例

    看了很多应用,觉得这种侧滑的抽屉效果的菜单很好. 不用切换到另一个页面,也不用去按菜单的硬件按钮,直接在界面上一个按钮点击,菜单就滑出来,而且感觉能放很多东西. 关于实现,搜索了一下,有如下两种: 1.用SlidingDrawer:http://developer.android.com/reference/android/widget/SlidingDrawer.html 但是不知道为什么这个类官方不建议再继续用了:Deprecated since API level 17 2.用Drawer

随机推荐