高仿QQ消息,可以下拉刷新带小红点
来源:互联网 发布:皮蓬生涯数据 编辑:程序博客网 时间:2024/06/10 09:34
最近在做即时通讯这一块,老板不知道怎么想的,反正完全是照着QQ做的,而我个人又非常喜欢qq侧滑操作这个效果,于是想找来用,但是翻遍了网络,没有一个像样的例子,有相似的也是各种bug各种限制,我也崩溃啊,没办法只好自己搞一个了。不多说上效果图:
具体实现呢,是自定义的listview来做的,本来的思路是自定义item的根布局来做,结果出来之后,事件的分发处理,特别不好弄,各种不流畅。
于是改用自定义listview,结果很喜人,个人觉得比较完美,支持3.0以下,
由于是属性动画需要支持到3.0以下,所以使用了nineoldandroid这个开源的属性动画库。
下面看代码:
public class InfoListView extends ListView { private int mScreenWidth; // 屏幕宽度 private float mDownX; // 按下点的x值 private float mDownY; // 按下点的y值 private int mActionViewWidth;// 操作view的宽度 /** * 执行动画的时间 */ protected long mAnimationTime = 150; private boolean isActionViewShow = false; // 删除按钮是否正在显示 private ViewGroup mPointChild; // 当前处理的item private LinearLayout.LayoutParams mLayoutParams; // 当前处理的item的LayoutParams private int touchSlop;//最小偏移量超过这个值才处理滑动事件 private float scroll;//偏移的距离 private int openedIntemPosition = -1;//记录已经打开的item的位置 private int childPosition;//手指落下位置的item的position private boolean iswiping = false;//手指是否正在滑动 private boolean isDownToNormal = false;//判断之前是否是手指落下导致消失。 private boolean isUPToNormal = false;//判断之前是否是手指离开导致消失。 private long lastTime;//计算手指两次的触摸间隔 public InfoListView(Context context) { this(context, null); } public InfoListView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public InfoListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // 获取屏幕宽度 WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(dm); mScreenWidth = dm.widthPixels; final ViewConfiguration configuration = ViewConfiguration.get(getContext()); touchSlop = configuration.getScaledTouchSlop(); } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: performActionDown(ev); break; case MotionEvent.ACTION_MOVE: return performActionMove(ev); case MotionEvent.ACTION_UP: performActionUp(ev); break; } return super.onTouchEvent(ev); } // 处理action_down事件 private void performActionDown(MotionEvent ev) { //如果触摸间隔小于100MS 不让进来~ if (System.currentTimeMillis() - lastTime <= mAnimationTime) { lastTime = System.currentTimeMillis(); return; } lastTime = System.currentTimeMillis(); mDownX = ev.getX(); mDownY = ev.getY(); if (isActionViewShow) { childPosition = pointToPosition((int) mDownX, (int) mDownY); if (childPosition == AdapterView.INVALID_POSITION) { return; } if ((openedIntemPosition != childPosition - getFirstVisiblePosition())) { //全部恢复初始值不作响应 turnToNormal(); isDownToNormal = true; mDownX = -1; mDownY = -1; return; } } if ((!isActionViewShow && openedIntemPosition == -1)) { // 获取当前点的item childPosition = pointToPosition((int) mDownX, (int) mDownY); if (childPosition == AdapterView.INVALID_POSITION) { return; } openedIntemPosition = childPosition - getFirstVisiblePosition(); mPointChild = (ViewGroup) getChildAt(openedIntemPosition); // 获取操作view宽度 mActionViewWidth = mPointChild.getChildAt(1).getLayoutParams().width; mLayoutParams = (LinearLayout.LayoutParams) mPointChild.getChildAt(0) .getLayoutParams(); // 为什么要重新设置layout_width 等于屏幕宽度 // 因为match_parent时,不管你怎么滑,都不会显示删除按钮 // why? 因为match_parent时,ViewGroup就不去布局剩下的view mLayoutParams.width = mScreenWidth; mPointChild.getChildAt(0).setLayoutParams(mLayoutParams); } } // 处理action_move事件 private boolean performActionMove(MotionEvent ev) { if ((Math.abs(ev.getX() - mDownX) > touchSlop && Math.abs(ev.getY() - mDownY) < touchSlop) || (Math.abs(ev.getX() - mDownX) > touchSlop && Math.abs(ev.getY() - mDownY) > touchSlop && (Math.abs(ev.getX() - mDownX) > Math.abs(ev.getY() - mDownY)))) { iswiping = true; //当手指滑动item,取消item的点击事件,不然我们滑动Item也伴随着item点击事件的发生 MotionEvent cancelEvent = MotionEvent.obtain(ev); cancelEvent.setAction(MotionEvent.ACTION_CANCEL | (ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); onTouchEvent(cancelEvent); } if (isActionViewShow) { childPosition = pointToPosition((int) mDownX, (int) mDownY); if (childPosition == AdapterView.INVALID_POSITION) { return true; } if ((openedIntemPosition != childPosition - getFirstVisiblePosition())) { //全部恢复初始值不作响应 turnToNormal(); isDownToNormal = true; mDownX = -1; mDownY = -1; iswiping = false; return true; } } if (iswiping) { scroll = ev.getX() - mDownX; if (Math.abs(scroll) <= mActionViewWidth) { if ((scroll <= 0 && !isActionViewShow)) { ViewHelper.setTranslationX(mPointChild.getChildAt(0), scroll); ViewHelper.setTranslationX(mPointChild.getChildAt(1), scroll); } else if ((scroll >= 0 && isActionViewShow && openedIntemPosition != -1)) { ViewHelper.setTranslationX(mPointChild.getChildAt(0), (scroll - mActionViewWidth)); ViewHelper.setTranslationX(mPointChild.getChildAt(1), (scroll - mActionViewWidth)); } } return true; } return super.onTouchEvent(ev); } // 处理action_up事件 private void performActionUp(MotionEvent ev) { if (!iswiping) { if (isActionViewShow && openedIntemPosition != -1) { isUPToNormal = true; turnToNormal(); } else { turnToNormal(); } return; } scroll = ev.getX() - mDownX; // 偏移量大于操作view的一半,则显示 // 否则恢复默认 //向左滑动 if (scroll < 0) { if ((-scroll >= mActionViewWidth / 4) && !isActionViewShow) { show(); } else if ((-scroll < mActionViewWidth / 4) || ((-scroll >= mActionViewWidth / 4) && isActionViewShow)) { if (isActionViewShow) { childPosition = pointToPosition((int) mDownX, (int) mDownY); if (childPosition == AdapterView.INVALID_POSITION) { return; } if (openedIntemPosition == childPosition - getFirstVisiblePosition()) { return; } } turnToNormal(); } } else if (scroll > 0) {//向右滑动 if (scroll < mActionViewWidth / 4 && isActionViewShow && openedIntemPosition != -1) { show(); } else if (scroll >= mActionViewWidth / 4 && isActionViewShow && openedIntemPosition != -1) { turnToNormal(); } else { //如果没有展开的其它情况全部恢复原样 turnToNormal(); } } iswiping = false; } @Override public boolean performItemClick(View view, int position, long id) { //当有展开的item的时候,不响应item的点击事件 if (isActionViewShow || isDownToNormal || isUPToNormal) { isDownToNormal = false; isUPToNormal = false; if (isActionViewShow && openedIntemPosition != -1) { turnToNormal(); } return false; } return super.performItemClick(view, position, id); } /** * 隐藏操作view */ public void turnToNormal() { if (mPointChild == null) { return; } isActionViewShow = false; ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mPointChild.getChildAt(0), "translationX", 0); ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(mPointChild.getChildAt(1), "translationX", mActionViewWidth); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether(objectAnimator, objectAnimator1); animatorSet.setDuration(mAnimationTime); animatorSet.start(); animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { openedIntemPosition = -1; } }); } /** * 显示操作view */ private void show() { if (mPointChild == null) { return; } isActionViewShow = true; ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mPointChild.getChildAt(0), "translationX", -mActionViewWidth); ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(mPointChild.getChildAt(1), "translationX", -mActionViewWidth); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether(objectAnimator, objectAnimator1); animatorSet.setDuration(mAnimationTime); animatorSet.start(); } /** * 是否显示 * @return */ public boolean isActionViewShow() { return isActionViewShow; }}
这里面需要注意的是item的布局:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" android:gravity="center_vertical" android:orientation="horizontal"> <!--初显示界面--> <LinearLayout android:id="@+id/id_front" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" android:paddingBottom="10dp" android:paddingLeft="10dp" android:paddingRight="10dp" android:paddingTop="10dp" android:orientation="horizontal"> <ImageView android:id="@+id/infoImage" android:layout_width="50dp" android:layout_height="50dp" android:layout_centerVertical="true" android:scaleType="centerCrop" android:src="@android:drawable/star_on" /> <LinearLayout android:layout_weight="3.0" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_centerVertical="true" android:layout_marginLeft="10dp" android:layout_toLeftOf="@+id/infoTimeAndCount" android:layout_toRightOf="@+id/infoImage" android:gravity="center_vertical" android:orientation="vertical"> <TextView android:id="@+id/infoTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Jay" /> <TextView android:textSize="13sp" android:id="@+id/infoLast" android:textColor="@android:color/darker_gray" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="什么事啊??" /> </LinearLayout> <LinearLayout android:layout_weight="1.0" android:id="@+id/infoTimeAndCount" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:gravity="center_vertical|right" android:orientation="vertical"> <TextView android:id="@+id/infoTime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Jay" /> <TextView android:id="@+id/infoCount" android:textSize="13sp" android:textColor="@android:color/white" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="99+" /> </LinearLayout> </LinearLayout> <!--滑动显示界面--> <LinearLayout android:id="@+id/id_back" android:layout_width="160dp" android:layout_height="70dp" android:background="@android:color/white" android:gravity="center|right" android:tag="id_back"> <TextView android:id="@+id/id_putTop" android:textSize="19sp" android:textColor="@android:color/white" android:layout_width="80dp" android:layout_height="match_parent" android:background="@android:color/darker_gray" android:clickable="true" android:gravity="center" android:text="置顶" /> <TextView android:id="@+id/id_delete" android:textSize="19sp" android:textColor="@android:color/white" android:layout_width="80dp" android:layout_height="match_parent" android:background="@color/red" android:clickable="true" android:gravity="center" android:text="删除" /> </LinearLayout></LinearLayout>
以上就是关键代码了,大家可以直接拿来用,附上源码下载地址:~
完美仿QQ消息界面功能
0 0
- 高仿QQ消息,可以下拉刷新带小红点
- 高仿QQ聊天消息列表的下拉刷新效果
- 高仿QQ下拉刷新之LoadView
- Android高仿QQ下拉刷新
- Android 轻松实现仿QQ消息下拉刷新
- Android 高仿QQ的下拉刷新 ListView
- 高仿QQlistview滑动删除+下拉刷新
- 高仿淘宝下拉刷新控件
- Android 轻松实现仿QQ空间下拉刷新
- 仿IOS版QQ的下拉刷新头实现原理
- 鹅厂系列四 : 仿QQ下拉刷新
- Android仿QQ下拉刷新、上拉回弹
- Android仿苹果版QQ下拉刷新实现(三)
- 高仿IOS下拉刷新的粘虫效果
- 高仿IOS下拉刷新的粘虫效果
- Android自定义之高仿淘宝下拉刷新
- Android QQ消息列表(下拉刷新 +item侧滑 )
- 仿QQ下拉菜单
- 中国融资租赁行业存在的问题
- mtk平台androidl usb uvc camera 调试记录
- 显示ActionBar的Menu
- linux光驱挂载和vsftpd服务安装使用
- VS+QT实现语言自动切换
- 高仿QQ消息,可以下拉刷新带小红点
- JAVA对list集合进行排序Collections.sort()
- 建立maven项目
- codeforces 604B (贪心)
- 47,结构体数组
- 分享一个win2003下 .bat 格式的打包,拷贝脚本
- RTCP中的NTP的时间计算方法
- 决策树系列算法总结(ID3, C4.5, CART, Random Forest, GBDT)
- 最短路径—Dijkstra算法和Floyd算法