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); }}
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
- Android开发之QQ侧滑面板
- android开发之仿QQ拖拽界面效果(侧滑面板)
- android开发之仿QQ拖拽界面效果(侧滑面板)
- 仿QQ侧滑面板(一)
- 仿QQ侧滑面板(二)
- 仿QQ侧滑面板(三)
- QQ侧滑面板特效的实现
- Android开发之QQ分享
- Android开发之高仿QQ消息侧拉删除
- Android 之打造QQ 侧滑菜单
- Android开发学习之仿手机QQ消息列表侧滑删除效果
- Android开发之仿QQ侧滑删除实现方式(一)
- Android开发之仿QQ侧滑删除实现(二)
- android开发之查询QQ是否在线
- Android开发之QQ直接登陆功能
- Android开发之-- 打开QQ临时聊天
- 自定义控件之侧滑面板
- Android 侧滑面板的实现(DragLayout)
- 图像滤镜艺术---霓虹、浮雕、木刻滤镜
- 北京约到信息科技有限公司
- jsp九大内置对象和四个作用域
- Java学习笔记01 编译和运行Java程序
- docker 构建网站初探
- Android开发之QQ侧滑面板
- 编译原理总结
- Axis2(WebService)经典教程
- 对 Jsp及Servlet 的简单剖析
- zoj3892Available Computation Sequence(区间dp)
- LeetCode Best Time to Buy and Sell Stock IV
- .net中ImageField绑定图片路径
- java 逆置 单链表
- hdu 5439 Aggregated Counting(找规律)