Android开发之QQ侧滑面板

来源:互联网 发布:u盘数据恢复文件乱码 编辑:程序博客网 时间:2024/05/16 10:43

Android开发之QQ侧滑面板

前段时间,腾讯手机QQ新版一推出,其QQ侧滑面板的炫酷效果让诸多的开发人员眼前一亮,这么炫酷的效果该怎么实现呢?本人稍稍研究了下,发现还算不是太难,基本效果差不多,下面贴出代码,望各位大神批评指正!

先效果图:


主要代码如下:
MainActivity
package com.hxht.testqqslidingpanel;import android.animation.ObjectAnimator;import android.app.Activity;import android.graphics.Color;import android.support.v7.app.ActionBarActivity;import android.os.Bundle;import android.util.Log;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.ViewGroup;import android.view.animation.CycleInterpolator;import android.widget.ArrayAdapter;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ListView;import android.widget.TextView;import android.widget.Toast;import com.hxht.testqqslidingpanel.customdragview.SlidingPanelDragView;import com.hxht.testqqslidingpanel.mylinerlayout.MyLinerlayout;import com.nineoldandroids.view.ViewHelper;import java.util.Random;public class MainActivity extends Activity {    private LinearLayout ll_leftview;    private ImageView iv_left_icon;    private ListView lv_left;    private MyLinerlayout ll_mainview;    private ImageView iv_main_icon;    private TextView tv_main;    private ListView lv_main;    private static final String[] names = new String[]{            "宋江",            "卢俊义",            "吴用",            "公孙胜",            "关胜",            "林冲",            "秦明",            "呼延灼",            "花荣",            "柴进",            "李应",            "朱仝",            "鲁智深",            "武松",            "董平",            "张清",            "杨志",            "徐宁",            "索超",            "戴宗",            "刘唐",            "李逵",            "史进",            "穆弘",            "雷横",            "李俊",            "阮小二",            "张横",            "阮小五",            "张顺",            "阮小七",            "杨雄",            "石秀",            "解珍",            "解宝 ",            "燕青",            "朱武",            "黄信",            "孙立",            "宣赞",            "郝思文",            "韩滔",            "彭玘",            "单廷圭",            "魏定国",            "萧让",            "裴宣",            "欧鹏",            "邓飞",            "燕顺",            "杨林",            "凌振",            "蒋敬",            "吕方",            "郭盛",            "安道全",            "皇甫端",            "王英",            "扈三娘",            "鲍旭",            "樊瑞",            "孔明",            "孔亮",            "项充",            "李衮",            "金大坚",            "马麟",            "童威",            "童猛",            "孟康",            "侯健",            "陈达",            "杨春",            "郑天寿",            "陶宗旺",            "宋清",            "乐和",            "龚旺",            "丁得孙",            "穆春",            "曹正",            "宋万",            "杜迁",            "薛永",            "李忠",            "周通",            "汤隆",            "杜兴",            "邹渊",            "邹润",            "朱贵",            "朱富",            "施恩",            "蔡福",            "蔡庆",            "李立",            "李云",            "焦挺",            "石勇",            "孙新",            "顾大嫂",            "孙二娘",            "王定六",            "郁保四",            "白胜",            "时迁",            "段景住"    };    private SlidingPanelDragView dragView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initViews();        initData();    }    private void initData() {        ll_mainview.setDragView(dragView);        lv_left.setAdapter(new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, names) {            @Override            public View getView(int position, View convertView, ViewGroup parent) {                TextView tv = (TextView) super.getView(position, convertView, parent);                tv.setTextColor(Color.WHITE);                return tv;            }        });        lv_main.setAdapter(new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, names) {            @Override            public View getView(int position, View convertView, ViewGroup parent) {                TextView tv = (TextView) super.getView(position, convertView, parent);                tv.setTextColor(Color.WHITE);                return tv;            }        });        dragView.setOnUpdateStatusListener(new SlidingPanelDragView.OnUpdateStatusListener() {            @Override            public void onOpen() {                //Toast.makeText(MainActivity.this, "打开了侧滑面板", Toast.LENGTH_SHORT).show();                Random random = new Random();                int index = random.nextInt(100);                System.out.println(index);                lv_left.smoothScrollToPosition(index);            }            @Override            public void onClose() {                //Toast.makeText(MainActivity.this, "关闭了侧滑面板", Toast.LENGTH_SHORT).show();                ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(iv_main_icon, "translationX", 15f);                objectAnimator.setInterpolator(new CycleInterpolator(4));                objectAnimator.setDuration(200);                objectAnimator.start();            }            @Override            public void onDraging(float percent) {                ViewHelper.setAlpha(iv_left_icon, percent);                ViewHelper.setAlpha(iv_main_icon, 1 - percent);                ViewHelper.setScaleX(tv_main, 1 - percent);                ViewHelper.setScaleY(tv_main, 1 - percent);            }        });    }    private void initViews() {        ll_leftview = (LinearLayout) findViewById(R.id.ll_leftview);        iv_left_icon = (ImageView) findViewById(R.id.iv_left_icon);        lv_left = (ListView) findViewById(R.id.lv_left);        ll_mainview = (MyLinerlayout) findViewById(R.id.ll_mainview);        iv_main_icon = (ImageView) findViewById(R.id.iv_main_icon);        tv_main = (TextView) findViewById(R.id.tv_main);        lv_main = (ListView) findViewById(R.id.lv_main);        dragView = (SlidingPanelDragView) findViewById(R.id.slidingpaneldragview);    }}

SlidingPanelDragView
package com.hxht.testqqslidingpanel.customdragview;import android.animation.ArgbEvaluator;import android.animation.FloatEvaluator;import android.content.Context;import android.graphics.Color;import android.graphics.PorterDuff;import android.support.v4.view.ViewCompat;import android.support.v4.widget.ViewDragHelper;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.FrameLayout;import com.nineoldandroids.view.ViewHelper;public class SlidingPanelDragView extends FrameLayout {    private ViewDragHelper mViewDragHelper;    private ViewGroup leftView;    private ViewGroup mainView;    private int mWidth;    private int mHeight;    private int range;    public enum Status {        OPEN,        CLOSE,        DRAGING    }    public interface OnUpdateStatusListener {        void onOpen();        void onClose();        void onDraging(float percent);    }    private Status status = Status.CLOSE;    private OnUpdateStatusListener onUpdateStatusListener;    public OnUpdateStatusListener getOnUpdateStatusListener() {        return onUpdateStatusListener;    }    public void setOnUpdateStatusListener(OnUpdateStatusListener onUpdateStatusListener) {        this.onUpdateStatusListener = onUpdateStatusListener;    }    public Status getStatus() {        return status;    }    public void setStatus(Status status) {        this.status = status;    }    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {        //第三步:处理监听        /**         * 试图去捕捉的View         * 返回true则表示该控件的所有子控件都能被聚焦         * 返回false则表示该控件的所有子控件都不能被聚焦         * @param child         * @param pointerId         * @return         */        @Override        public boolean tryCaptureView(View child, int pointerId) {            return true;        }        @Override        public int clampViewPositionHorizontal(View child, int left, int dx) {            if (child == mainView) {                left = fixLeft(left);            }            return left;        }        @Override        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {            super.onViewPositionChanged(changedView, left, top, dx, dy);            int newLeft = mainView.getLeft();            if (changedView == mainView) {                newLeft = left;            } else {                newLeft += dx;            }            newLeft = fixLeft(newLeft);            if (changedView == leftView) {                leftView.layout(0, 0, mWidth, mHeight);                mainView.layout(newLeft, 0, newLeft + mWidth, mHeight);            }            dispatchDragEvent(newLeft);            invalidate();//为了兼容低版本,在此处需要重绘        }        @Override        public void onViewReleased(View releasedChild, float xvel, float yvel) {            super.onViewReleased(releasedChild, xvel, yvel);            if (mainView.getLeft() > range / 2 && xvel == 0) {                open();            } else if (xvel > 0) {                open();            } else {                close();            }        }        @Override        public int getViewHorizontalDragRange(View child) {            return super.getViewHorizontalDragRange(child);        }        @Override        public void onViewCaptured(View capturedChild, int activePointerId) {            super.onViewCaptured(capturedChild, activePointerId);        }        @Override        public void onViewDragStateChanged(int state) {            super.onViewDragStateChanged(state);        }    };    /**     * 更新状态     * @param newLeft     */    private void dispatchDragEvent(int newLeft) {        //在位置变化的同时,执行伴随动画等等        float percent = newLeft * 1.0f / range;        animViews(percent);        if (onUpdateStatusListener != null ){            onUpdateStatusListener.onDraging(percent);        }        Status lastStatus = status ;        status = updateStatus(percent);        if (lastStatus != status){            if (onUpdateStatusListener != null){                if (status == Status.CLOSE){                    onUpdateStatusListener.onClose();                }else if (status == Status.OPEN){                    onUpdateStatusListener.onOpen();                }            }        }    }    /**     * 更新状态     * @param percent     * @return     */    private Status updateStatus(float percent) {        if (percent == 0){            return Status.CLOSE;        }else if (percent == 1){            return Status.OPEN;        }else{            return Status.DRAGING;        }    }    private void animViews(float percent) {        //percent的变化范围为 0.1 ---> 1.0        //在位置变化时让控件做伴随动画        //首先让主控件随着percent做缩放动画即从1.0--->0.8        //float mainPercent = 0.8f + (1 - percent) * 0.2f ;        //float leftPercent = 0.5f + (1 - percent) * 0.5f ;        //第一种方式:        //mainView.setScaleX(mainPercent);        //mainView.setScaleY(mainPercent);        //leftView.setScaleX(leftPercent);        //leftView.setScaleY(leftPercent);        //第二种写法,适用类型估值器        FloatEvaluator floatEvaluator = new FloatEvaluator();        Float mainPercent = floatEvaluator.evaluate(percent, 1.0f, 0.8f);        Float leftPercent = floatEvaluator.evaluate(percent, 0.5f, 1.0f);        Float leftTranslationPercent = floatEvaluator.evaluate(percent, -mWidth / 2f, 0);        ViewHelper.setScaleX(mainView, mainPercent);        ViewHelper.setScaleY(mainView, mainPercent);        ViewHelper.setScaleX(leftView, leftPercent);        ViewHelper.setScaleY(leftView, leftPercent);        ViewHelper.setTranslationX(leftView, leftTranslationPercent);        ArgbEvaluator argbEvaluator = new ArgbEvaluator();        Integer color = (Integer) argbEvaluator.evaluate(percent, Color.BLACK, Color.TRANSPARENT);        getBackground().setColorFilter(color, PorterDuff.Mode.SRC_OVER);    }    private int finalLeft;    /**     * postInvalidateOnAnimation催动执行,重绘     */    @Override    public void computeScroll() {        super.computeScroll();        //触发一个平滑的滚动事件,若返回true则表示没有滚动到指定位置,则需要重绘        if (mViewDragHelper.continueSettling(true)) {            ViewCompat.postInvalidateOnAnimation(this);        }    }    /**     * 定义关闭侧滑面板的方法     */    public void close() {        toSmoothClose(true);    }    /**     * 定义方法去平滑的关闭侧滑面板     *     * @param isSmooth     */    private void toSmoothClose(boolean isSmooth) {        finalLeft = 0;        toSmoothOpenOrClose(isSmooth);    }    /**     * 定义打开侧滑面板的方法     */    private void open() {        toSmoothOpen(true);    }    /**     * 定义方法去平滑的打开侧滑面板     *     * @param isSmooth     */    private void toSmoothOpen(boolean isSmooth) {        finalLeft = range;        toSmoothOpenOrClose(isSmooth);    }    /**     * 定义方法平滑的关闭或打开侧滑面板     *     * @param isSmooth     */    private void toSmoothOpenOrClose(boolean isSmooth) {        if (isSmooth) {            //触发一个平滑的滚动事件,若返回true则表示没有滚动到指定位置,则需要重绘            if (mViewDragHelper.smoothSlideViewTo(mainView, finalLeft, 0)) {                //引发重绘                //第一种写法:                //invalidate();                //第二种写法:                //该方法调用computeScroll方法的执行                ViewCompat.postInvalidateOnAnimation(this);            }        } else {            mainView.layout(finalLeft, 0, finalLeft + mWidth, mHeight);        }    }    /**     * 修正Left的值     *     * @param left     * @return     */    private int fixLeft(int left) {        if (left < 0) {            return 0;        } else if (left > range) {            return range;        } else {            return left;        }    }    public SlidingPanelDragView(Context context) {        this(context, null);    }    public SlidingPanelDragView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public SlidingPanelDragView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //第一步:初始化ViewDragHelper对象,由于ViewDragHelper的构造方法被私有化,所以采用create方法实例化对象        mViewDragHelper = ViewDragHelper.create(this, callback);    }    //第二步:托管触摸事件    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        return mViewDragHelper.shouldInterceptTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        try {            mViewDragHelper.processTouchEvent(event);        } catch (Exception e) {            e.printStackTrace();        }        return true;    }    /**     * xml加载完成后调用此方法,故可在此方法中拿到该控件的子View     */    @Override    protected void onFinishInflate() {        super.onFinishInflate();        if (getChildCount() < 2) {            throw new IllegalArgumentException("This view must hava two children at least!");        }        if (!(getChildAt(0) instanceof ViewGroup) || !(getChildAt(1) instanceof ViewGroup)) {            throw new IllegalArgumentException("The children must be instanceof ViewGroup");        }        leftView = (ViewGroup) getChildAt(0);        mainView = (ViewGroup) getChildAt(1);    }    /**     * 该方法的执行会催动onMesture方法的执行,故可在此方法中拿到控件的高度和宽度     *     * @param w     * @param h     * @param oldw     * @param oldh     */    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        mWidth = getMeasuredWidth();        mHeight = getMeasuredHeight();        range = (int) (mWidth * 0.6f);    }}

MyLinerlayout
package com.hxht.testqqslidingpanel.mylinerlayout;import android.content.Context;import android.support.v4.view.MotionEventCompat;import android.util.AttributeSet;import android.view.MotionEvent;import android.widget.LinearLayout;import com.hxht.testqqslidingpanel.customdragview.SlidingPanelDragView;public class MyLinerlayout extends LinearLayout {    private SlidingPanelDragView dragView ;    public MyLinerlayout(Context context) {        super(context);    }    public MyLinerlayout(Context context, AttributeSet attrs) {        super(context, attrs);    }    public MyLinerlayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    public void setDragView(SlidingPanelDragView dragView) {        this.dragView = dragView;    }    /**     * 是否拦截事件     * 返回true则拦截     * 返回false则不拦截     * @param ev     * @return     */    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        if (dragView.getStatus() == SlidingPanelDragView.Status.CLOSE){            return super.onInterceptTouchEvent(ev);        }else{            return true;        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        if (dragView.getStatus() == SlidingPanelDragView.Status.CLOSE){            return super.onTouchEvent(event);        }else{            //if (event.getAction() == MotionEvent.ACTION_UP){            //    dragView.close();            //}            if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_UP){                dragView.close();            }            return true;        }    }}

代码已贴出,正所谓取之于社会,回报与社会,望各路大神批评指正,不喜勿喷,非常感谢!

本Demo下载地址:https://github.com/FlyingSnow2211/QQSlidingPanel




0 0
原创粉丝点击