Android 高仿 QQ5.2 侧滑菜单效果及QQmini效果

参考了:Android的高仿QQ5.0侧滑菜单效果自定义控件来袭

然后自己撰写了QQ5.2效果,并且可以切换QQmini效果,个人话语不多,见谅!

本人已经开源到了TaoCode,可以使用SVN免费更新下载:
http://code.taobao.org/svn/imitateqqandqqmini/trunk
本人TaoCode首页

CSDN:点击下载
qq5.0效果:


qq5.2效果:

qqmini效果:



首先看下布局:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/ic_launcher" >

    <com.bluemor.reddotface.view.DragLayout
        android:id="@+id/dl"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <FrameLayout
            android:id="@+id/flBack"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <ListView
                android:id="@+id/lv"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:cacheColorHint="#00000000"
                android:divider="@null"
                android:scrollbarSize="0dp"
                android:scrollbars="@null" />
        </FrameLayout>

        <com.bluemor.reddotface.view.MyFrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#eeeeee" >

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

                <RelativeLayout
                    android:id="@+id/rl_title"
                    android:layout_width="match_parent"
                    android:layout_height="55dp"
                    android:background="#3683C1" >

                    <ImageView
                        android:id="@+id/iv_icon"
                        android:layout_width="42dp"
                        android:layout_height="42dp"
                        android:layout_centerVertical="true"
                        android:layout_marginLeft="10dp"
                        android:scaleType="centerCrop"
                        android:src="@drawable/ic_launcher" />

                    <Button
                        android:id="@+id/btn"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true"
                        android:text="@string/app_name"
                        android:textColor="#ffffff"
                        android:textSize="20sp" />
                </RelativeLayout>

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_below="@id/rl_title"
                    android:text="@string/text" />
            </RelativeLayout>
        </com.bluemor.reddotface.view.MyFrameLayout>
    </com.bluemor.reddotface.view.DragLayout>
</FrameLayout>


然后,子布局(前面的显示的):

package com.bluemor.reddotface.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.FrameLayout;

import com.bluemor.reddotface.view.DragLayout.Status;

/**
 * @author chenyingyou
 * @see http://blog.csdn.net/chenlove1
 */
public class MyFrameLayout extends FrameLayout {
	private DragLayout dl;

	public MyFrameLayout(Context context) {
		super(context);
	}

	public MyFrameLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

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

	public void setDragLayout(DragLayout dl) {
		this.dl = dl;
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent event) {
		if (dl.getStatus() != Status.Close) {
			return true;
		}
		return super.onInterceptTouchEvent(event);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (dl.getStatus() != Status.Close) {
			if (event.getAction() == MotionEvent.ACTION_UP) {
				dl.close();
			}
			return true;
		}
		return super.onTouchEvent(event);
	}

}



最后,父布局(后面的布局):

package com.bluemor.reddotface.view;

import android.content.Context;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;

import com.bluemor.reddotface.R;
import com.nineoldandroids.view.ViewHelper;

/**
 * @author chenyingyou
 * @see http://blog.csdn.net/chenlove1
 */
public class DragLayout extends FrameLayout {

	private boolean isShowShadow = true;
	private boolean isQQEffect = true;

	private GestureDetectorCompat gestureDetector;// 拦截手势判断
	private ViewDragHelper dragHelper;// 拦截后的手势监听
	private DragListener dragListener;// 外界回调

	private int rangeLeft;// 左边的拉开宽度
	private int rangeRight;// 右边的拉开宽度
	private final float ratioLeft = 0.5f;// 左边的拉开系数
	private final float ratioRight = 0.25f;// 右边的拉开系数
	private int width;// 宽度
	private int height;// 高度
	private int shifting;// shifting偏移量(正数为左边偏移量,负数为右边偏移量)

	private ImageView ivshadow;
	private FrameLayout flBackground;
	private MyFrameLayout flMain;

	private Status status = Status.Close;

	public enum Status {
		Drag, OpenLeft, OpenRight, Close
	}

	public DragLayout(Context context) {
		this(context, null);
	}

	public DragLayout(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public DragLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		gestureDetector = new GestureDetectorCompat(context,
				new YScrollDetector());
		dragHelper = ViewDragHelper.create(this, dragHelperCallback);
	}

	class YScrollDetector extends SimpleOnGestureListener {
		@Override
		public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx,
				float dy) {
			return Math.abs(dy) <= Math.abs(dx);
		}
	}

	// 拦截后的手势监听回调
	private ViewDragHelper.Callback dragHelperCallback = new ViewDragHelper.Callback() {

		@Override
		public int clampViewPositionHorizontal(View child, int left, int dx) {
			if (shifting + dx < rangeRight) {// 向左拉
				return rangeRight;
			} else if (shifting + dx > rangeLeft) {// 向右拉
				return rangeLeft;
			} else {
				return left;
			}
		}

		@Override
		public boolean tryCaptureView(View child, int pointerId) {
			return true;
		}

		@Override
		public int getViewHorizontalDragRange(View child) {
			return width;
		}

		@Override
		// 当手势触发到抬起动作
		public void onViewReleased(View releasedChild, float xvel, float yvel) {
			super.onViewReleased(releasedChild, xvel, yvel);

			if (shifting > 0) {
				if (xvel > 0) {// 最后向右滑
					openLeft();
				} else if (xvel < 0) {// 最后向左滑
					close();
				} else if (releasedChild == flMain
						&& shifting > rangeLeft * 0.3) {
					openLeft();
				} else if (releasedChild == flBackground
						&& shifting > rangeLeft * 0.7) {
					openLeft();
				} else {
					close();
				}
			} else {
				if (xvel > 0) {
					close();
				} else if (xvel < 0) {
					openRight();
				} else if (releasedChild == flMain
						&& shifting > rangeRight * 0.3) {
					close();
				} else if (releasedChild == flBackground
						&& shifting > rangeRight * 0.7) {
					close();
				} else {
					close();
				}
			}

		}

		@Override
		// 当手势触发到了某个changedView回调这方法
		public void onViewPositionChanged(View changedView, int left, int top,
				int dx, int dy) {
			if (changedView == flMain) {
				shifting = left;
			} else {
				shifting = shifting + left;
			}

			if (shifting < rangeRight) {
				shifting = rangeRight;
			} else if (shifting > rangeLeft) {
				shifting = rangeLeft;
			}

			if (isShowShadow) {
				ivshadow.layout(shifting, 0, shifting + width, height);
			}

			if (changedView == flBackground) {
				flMain.layout(shifting, 0, shifting + width, height);
				flBackground.layout(0, 0, width, height);
			}

			dispatchDragEvent(shifting);
		}
	};

	private void dispatchDragEvent(int shifting) {
		float percent;
		boolean isLeft;

		if (shifting < 0) {
			isLeft = false;
			percent = shifting / (float) rangeRight;
		} else {
			isLeft = true;
			percent = shifting / (float) rangeLeft;
		}

		if (dragListener != null) {
			dragListener.onDrag(percent, isLeft);
			Status lastStatus = status;
			if (lastStatus != getStatus() && status == Status.Close) {
				dragListener.onClose();
			} else if (lastStatus != getStatus() && status == Status.OpenLeft) {
				dragListener.openLeft();
			} else if (lastStatus != getStatus() && status == Status.OpenRight) {
				dragListener.openRight();
			}
		}

		if (!isQQEffect) {
			setBackgroundColor(evaluate(percent, 0x77777777, 0));
			return;
		}

		float f1 = 1 - percent * 0.2f;
		ViewHelper.setScaleX(flMain, f1);
		ViewHelper.setScaleY(flMain, f1);

		float translationX;
		float ratioX = 1.8f;
		if (isLeft) {
			translationX = -flBackground.getWidth() / ratioX
					+ flBackground.getWidth() / ratioX * percent;
		} else {
			translationX = flBackground.getWidth() / ratioX
					- flBackground.getWidth() / ratioX * percent;
		}
		ViewHelper.setTranslationX(flBackground, translationX);
		ViewHelper.setScaleX(flBackground, 0.5f + 0.5f * percent);
		ViewHelper.setScaleY(flBackground, 0.5f + 0.5f * percent);
		ViewHelper.setAlpha(flBackground, percent);
		if (isShowShadow) {
			ViewHelper.setScaleX(ivshadow, f1 * 1.8f * (1 - percent * 0.12f));
			ViewHelper.setScaleY(ivshadow, f1 * 1.8f * (1 - percent * 0.12f));
		}
		setBackgroundColor(evaluate(percent, 0xDD000000, 0));

	}

	private static Integer evaluate(float fraction, Integer startValue,
			Integer endValue) {
		int startInt = startValue;
		int startA = (startInt >> 24) & 0xff;
		int startR = (startInt >> 16) & 0xff;
		int startG = (startInt >> 8) & 0xff;
		int startB = startInt & 0xff;
		int endInt = (Integer) endValue;
		int endA = (endInt >> 24) & 0xff;
		int endR = (endInt >> 16) & 0xff;
		int endG = (endInt >> 8) & 0xff;
		int endB = endInt & 0xff;
		return (int) ((startA + (int) (fraction * (endA - startA))) << 24)
				| (int) ((startR + (int) (fraction * (endR - startR))) << 16)
				| (int) ((startG + (int) (fraction * (endG - startG))) << 8)
				| (int) ((startB + (int) (fraction * (endB - startB))));
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		return dragHelper.shouldInterceptTouchEvent(ev)
				&& gestureDetector.onTouchEvent(ev);
	}

	@Override
	public boolean onTouchEvent(MotionEvent e) {
		try {
			dragHelper.processTouchEvent(e);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return false;
	}

	@Override
	// 加载完成xml后,就会执行那个方法
	protected void onFinishInflate() {
		super.onFinishInflate();
		if (isShowShadow) {
			ivshadow = new ImageView(getContext());
			ivshadow.setImageResource(R.drawable.shadow);
			LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
					LayoutParams.MATCH_PARENT);
			addView(ivshadow, 1, lp);
		}
		flBackground = (FrameLayout) getChildAt(0);
		flMain = (MyFrameLayout) getChildAt(isShowShadow ? 2 : 1);
		flMain.setDragLayout(this);
		flBackground.setClickable(true);
		flMain.setClickable(true);
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		width = flBackground.getMeasuredWidth();
		height = flBackground.getMeasuredHeight();
		rangeLeft = (int) (width * ratioLeft);
		rangeRight = -(int) (width * ratioRight);
	}

	@Override
	public void computeScroll() {
		if (dragHelper.continueSettling(true)) {
			ViewCompat.postInvalidateOnAnimation(this);
		}
	}

	public Status getStatus() {
		if (shifting == 0) {
			status = Status.Close;
		} else if (shifting == rangeLeft) {
			status = Status.OpenLeft;
		} else if (shifting == rangeRight) {
			status = Status.OpenRight;
		} else {
			status = Status.Drag;
		}
		return status;
	}

	public void openLeft() {
		openLeft(true);
	}

	public void openLeft(boolean animate) {
		if (animate) {
			if (dragHelper.smoothSlideViewTo(flMain, rangeLeft, 0)) {
				ViewCompat.postInvalidateOnAnimation(this);
			}
		} else {
			flMain.layout(rangeLeft, 0, rangeLeft * 2, height);
			dispatchDragEvent(rangeLeft);
		}
	}

	public void openRight() {
		openRight(true);
	}

	public void openRight(boolean animate) {
		if (animate) {
			if (dragHelper.smoothSlideViewTo(flMain, rangeRight, 0)) {
				ViewCompat.postInvalidateOnAnimation(this);
			}
		} else {
			flMain.layout(rangeRight, 0, rangeRight * 2, height);
			dispatchDragEvent(rangeRight);
		}
	}

	public void close() {
		close(true);
	}

	public void close(boolean animate) {
		if (animate) {
			if (dragHelper.smoothSlideViewTo(flMain, 0, 0)) {
				ViewCompat.postInvalidateOnAnimation(this);
			}
		} else {
			flMain.layout(0, 0, width, height);
			dispatchDragEvent(0);
		}
	}

	/** 设置是否要QQ效果 */
	public void setIsQQEffect(boolean isQQEffect) {
		this.isQQEffect = isQQEffect;
		if (!isQQEffect) {
			ViewHelper.setTranslationX(flBackground, 0);
			ViewHelper.setScaleX(flBackground, 1);
			ViewHelper.setScaleY(flBackground, 1);
			ViewHelper.setAlpha(flBackground, 1);
		}
	}

	public boolean isQQEffect() {
		return isQQEffect;
	}

	/** 不需要右边侧滑 */
	public void setNotUsedRight() {
		rangeRight = 0;
	}

	/** 不需要左边侧滑 */
	public void setNotUsedLeft() {
		rangeRight = 0;
	}

	public void setDragListener(DragListener dragListener) {
		this.dragListener = dragListener;
	}

}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值