android开源项目(一) AndroidSideMenu

SlidingMenu实现的效果如下:


   

       最近直接拿来用!很火的android开源项目真的很牛,作为菜鸟我也要学习大神们的经验,牛顿曾说过:“如果说我看的远,那是因为站在巨人的肩膀上”

AndroidSideMenu的来源是github 代码库中的开源项目:路径如下:git://github.com/dmitry-zaitsev/AndroidSideMenu.git

    那么怎样把github代码仓库中的项目导入到我们常用的Eclipse中呢?详细步骤请看下面:

1.首先安装EGit插件,如果已有可以略过。

   在eclipse的help中选择Eclipse Marketplace 在find中输入egit就会出现如下界面

 

点击install, 等待安装完毕

 

然后接受安装协议

然后eclipse就开始安装EGit

片刻后,EGit就可以安装好了,


2.克隆Git仓库上的代码到本地电脑,并在Eclipse中查看Git中的工程

1.步骤如下:file—Import---Git--ProjectFromGit--URI


2.从git://github.com/dmitry-zaitsev/AndroidSideMenu.git 地址中clone  androidslidingMenu项目,

默认next 后出现以下,


继续默认next,选择克隆代码存放的位置


clon完毕后会出现以下选择界面


这样就可以导入从Git上下载的工程了


在eclipse中的布局如下


当我们导入从Git中下载好后的东西,我们却发现运行不了,我在网上也收了很多方法,可惜可有收到怎样解决的方法,如果谁有好的方法可以给我说说,

我的解决方法如下:

3.创建android工程

新建一个android工程,然后将布局,实现的代码等复制进去,修改修改最后终于给弄好了,不过呢,这个android工程要求建立的版本的在android 3.0之上的才可以运行,我试着建立常用的2.3.3 或则3.0以下的版本,结果发现有点不兼容...不知道那些牛逼的应用中怎样解决这个兼容性的问题的...

我创建好的工程源码下载地址:点击打开链接

实现的效果如下:


实现的布局如下:

<com.nyist.net.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=".Test3Activity" >

    <ScrollView
        android:layout_width="280dp"
        android:layout_height="fill_parent"
        android:background="@drawable/navigation_background" >

        <LinearLayout
            android:layout_width="280dp"
            android:layout_height="wrap_content"
             android:drawableRight="@drawable/btn_right"
            android:padding="1dp"
            android:orientation="vertical" >

            <Button
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:text="我的音乐" />

            <Button
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                 android:drawableRight="@drawable/btn_right"
                android:text="推荐" />

            <Button
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                 android:drawableRight="@drawable/btn_right"
                android:text="歌单" />

            <Button
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                 android:drawableRight="@drawable/btn_right"
                android:text="搜索" />

            <Button
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                 android:drawableRight="@drawable/btn_right"
                android:text="排行榜" />

            <Button
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                 android:drawableRight="@drawable/btn_right"
                android:text="歌手" />

            <Button
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:drawableRight="@drawable/btn_right"
                android:text="淘歌" />
        </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:background="@drawable/guider_03"
            android:textSize="25sp" />
    </RelativeLayout>

</com.nyist.net.SlideHolder>

布局引用的代码如下:

package com.nyist.net;
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);
	}

}


ps:这个工程要求是在android 3.0之上的版本

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员Android

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值