怎样怎么才能知道照片像素弄出像QQ那样的联系人列表

查看: 2098|回复: 2
请问怎么做出类似QQ好友列表那样的东西
该用户从未签到
需要什么第三方控件么,如果不用能做出来么,我想把软件快捷方式集中起来,类似音速启动的功能,但是要qq那样的界面
该用户从未签到
居然没有人顶。
该用户从未签到
厉害要是这么容易QQ早就关门大吉了  1)打开手机QQ,首先点击主页下方中央的【联系人】,然后进入【群聊】;(如下图)
  2)接着选择所要设置的群组并【左拉】,最后点击【设为常用群聊】便可。(如下图)listview侧滑菜单的实现——高仿QQ联系人列表 - CSDN博客
listview侧滑菜单的实现——高仿QQ联系人列表
转载请注明出处:
项目用到了的侧滑删除的功能,由于当时项目比较赶,就随便在网上找了一个,但是效果不是太好,最近闲了下来,就想自己实现一个,于是就按照的联系人列表的侧滑菜单做了一个,效果基本上是一模一样的。在这个过程中,自己也学习到了不少的东西,下面就把这个过程跟大家分享出来。
废话不多说,首先上效果图。
看完了图如果感觉效果不好,请不要拍砖,好的话请继续往下看
下面结合代码说说实现的原理:首先自定义一个来实现的滑动效果。
package com.binbin.slidedelmenu.
import android.content.C
import android.os.B
import android.support.annotation.RequiresA
import android.support.v4.widget.ViewDragH
import android.util.AttributeS
import android.util.L
import android.view.GestureD
import android.view.MotionE
import android.view.VelocityT
import android.view.V
import android.view.ViewC
import android.view.ViewG
import android.widget.BaseA
import android.widget.FrameL
import android.widget.ListA
import android.widget.ListV
import android.widget.S
* Created by -- on .
* 带侧滑菜单的自定义item
public class MenuItem extends ViewGroup {
private int contentW
private Scroller mS
private int maxWidth,maxH//viewGroup的宽高
private static final int MIN_FLING_VELOCITY = 600; // dips per second
/**最小滑动距离,超过了,才认为开始滑动
private int mTouchSlop = 0 ;
/**上次触摸的X坐标*/
private float mLastX = -1;
/**第一次触摸的X坐标*/
private float mFirstX = -1;
//防止多只手指一起滑动的flag 在每次down里判断, touch事件结束清空
private static boolean isT
private int mRightMenuW//右侧菜单总宽度
private VelocityTracker mVelocityT
private float mMaxV
private int mPointerId;//多点触摸只算第一根手指的速度
private boolean isQQ=//是否是qq效果
private boolean qqInterceptF//qq效果判断标志
private static MenuItem mViewC//存储的是当前正在展开的View
private boolean isUserS// 判断手指起始落点,如果距离属于滑动了,就屏蔽一切点击事件
//仿QQ,侧滑菜单展开时,点击除侧滑菜单之外的区域,关闭侧滑菜单。
//增加一个布尔值变量,dispatch函数里,每次down时,为true,move时判断,如果是滑动动作,设为false。
//在Intercept函数的up时,判断这个变量,如果仍为true 说明是点击事件,则关闭菜单。
private boolean isUnMoved =
public MenuItem(Context context) {
this(context,null);
public MenuItem(Context context, AttributeSet attrs) {
this(context, attrs,0);
public MenuItem(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public MenuItem(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
private void init(){
contentWidth=getContext().getResources().getDisplayMetrics().widthP
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
mScroller=new Scroller(getContext());
mMaxVelocity = ViewConfiguration.get(getContext()).getScaledMaximumFlingVelocity();
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setClickable(true);//令自己可点击,从而获取触摸事件(很重要,必须写在onMesaure中)
mRightMenuWidths=0;//由于ViewHolder的复用机制,每次这里要手动恢复初始值
* 根据childView计算的出的宽和高,计算容器的宽和高,主要用于容器是warp_content时
for (int i = 0,count = getChildCount(); i & i++) {
View childView = getChildAt(i);
//令每一个子View可点击,从而获取触摸事件
childView.setClickable(true);
if(childView.getVisibility()!=View.GONE){
//获取每个子view的自己高度宽度,取最大的就是viewGroup的大小
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
maxWidth = Math.max(maxWidth,childView.getMeasuredWidth());
maxHeight = Math.max(maxHeight,childView.getMeasuredHeight());
if(i&0){//第一个是content,后面的都是菜单
if(childView.getLayoutParams().width== LayoutParams.MATCH_PARENT){
//菜单的宽不能MATCH_PARENT
throw new IllegalArgumentException(&======menu'width can't be MATCH_PARENT=====&);
mRightMenuWidths+=childView.getMeasuredWidth();
if(childView.getLayoutParams().width!= LayoutParams.MATCH_PARENT){
//content的宽必须MATCH_PARENT
throw new IllegalArgumentException(&======content'width must be MATCH_PARENT=====&);
//为ViewGroup设置宽高
setMeasuredDimension(maxWidth,maxHeight);
ratio=mRightMenuWidths/3;//可能每个item的菜单不同,所以ratio要每次计算
* 根据最大宽高重新设置子view,保证高度充满
//首先判断params.width的值是多少,有三种情况。
//如果是大于零的话,及传递的就是一个具体的值,那么,构造MeasupreSpec的时候可以直接用EXACTLY。
//如果为-1的话,就是MatchParent的情况,那么,获得父View的宽度,再用EXACTLY来构造MeasureSpec。
//如果为-2的话,就是wrapContent的情况,那么,构造MeasureSpec的话直接用一个负数就可以了。
for (int i = 0,count = getChildCount(); i & i++) {
View childView = getChildAt(i);
if(childView.getVisibility()!=View.GONE){
//宽度采用测量好的
int widthSpec = MeasureSpec.makeMeasureSpec(childView.getMeasuredWidth(), MeasureSpec.EXACTLY);
//高度采用最大的
int heightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY);
childView.measure(widthSpec, heightSpec);
protected void onLayout(boolean changed, int l, int t, int r, int b) {
Log.e(&tianbin&,content.getMeasuredWidth()+&#&+content.getMeasuredHeight()+&$$$&+menu.getMeasuredWidth()+&#&+menu.getMeasuredHeight());
int left=0;
for (int i = 0; i & getChildCount(); i++) {
View childView = getChildAt(i);
if (childView.getVisibility() != GONE) {
if (i == 0) {//第一个子View是内容 宽度设置为全屏
childView.layout(0, 0, maxWidth, maxHeight);
left += maxW
childView.layout(left, 0, left + childView.getMeasuredWidth(), getPaddingTop() + maxHeight);
left += childView.getMeasuredWidth();
public boolean dispatchTouchEvent(MotionEvent ev) {
acquireVelocityTracker(ev);
final VelocityTracker verTracker = mVelocityT
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
Log.e(&tianbin&,&======MenuItem dispatchTouchEvent======ACTION_DOWN===&+isTouching);
if (isTouching) {//如果有别的指头摸过了,那么就return false。这样后续的move...等事件也不会再来找这个View了。
isTouching =//第一个摸的指头,赶紧改变标志,宣誓主权。
mLastX=ev.getRawX();
mFirstX=ev.getRawX();
//求第一个触点的id, 此时可能有多个触点,但至少一个,计算滑动速率用
mPointerId = ev.getPointerId(0);
isUserSwiped =
qqInterceptFlag=
isUnMoved=
//如果down,view和cacheview不一样,则立马让它还原。且把它置为null
if (mViewCache != null) {
if (mViewCache != this) {
mViewCache.smoothClose();
qqInterceptFlag = isQQ;//当前有侧滑菜单的View,且不是自己的,就该拦截事件咯。
//只要有一个侧滑菜单处于打开状态, 就不给外层布局上下滑动了
getParent().requestDisallowInterceptTouchEvent(true);
case MotionEvent.ACTION_MOVE:
if(qqInterceptFlag){//当前有侧滑菜单的View,且不是自己的,就该拦截事件咯。滑动也不该出现
Log.e(&tianbin&,&======MenuItem dispatchTouchEvent======ACTION_MOVE===11&);
float deltaX= ev.getRawX()-mLastX;
mLastX=ev.getRawX();
//为了在水平滑动中禁止父类ListView等再竖直滑动
if (Math.abs(deltaX) & 10 || Math.abs(getScrollX()) & 10) {//使屏蔽父布局滑动更加灵敏,
getParent().requestDisallowInterceptTouchEvent(true);
Log.e(&tianbin&,&======MenuItem dispatchTouchEvent======ACTION_MOVE===222&);
if (Math.abs(deltaX) & mTouchSlop) {
isUnMoved =
scrollBy(-(int)deltaX,0);
//越界修正
if (getScrollX() & 0) {
scrollTo(0, 0);
if (getScrollX() & mRightMenuWidths) {
scrollTo(mRightMenuWidths, 0);
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
Log.e(&tianbin&,&======MenuItem dispatchTouchEvent======ACTION_UP===&);
if (Math.abs(ev.getRawX() - mFirstX) & mTouchSlop) {
isUserSwiped =
if(!qqInterceptFlag){
//求伪瞬时速度
puteCurrentVelocity(1000, mMaxVelocity);
final float velocityX = verTracker.getXVelocity(mPointerId);
Log.e(&tianbin&,qqInterceptFlag+&=============velocityX:&+velocityX);
if (Math.abs(velocityX) & 1000) {//滑动速度超过阈值
if (velocityX & -1000) {
//平滑展开Menu
smoothExpand();
// 平滑关闭Menu
smoothClose();
if (Math.abs(getScrollX()) & ratio) {//否则就判断滑动距离
//平滑展开Menu
smoothExpand();
// 平滑关闭Menu
smoothClose();
releaseVelocityTracker();
isTouching =//没有手指在摸我了
return super.dispatchTouchEvent(ev);
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_MOVE:
//屏蔽滑动时的事件(长按事件和侧滑的冲突)
Log.e(&tianbin&,&======MenuItem onInterceptTouchEvent======ACTION_MOVE===111&);
if (Math.abs(ev.getRawX() - mFirstX) & mTouchSlop) {
Log.e(&tianbin&,&======MenuItem onInterceptTouchEvent======ACTION_MOVE===22222&);
case MotionEvent.ACTION_UP:
if (getScrollX() & mTouchSlop) {
//这里判断落点在内容区域屏蔽点击,内容区域外,允许传递事件继续向下的。。。
if (ev.getX() & getWidth() - getScrollX()) {
//仿QQ,侧滑菜单展开时,点击内容区域,关闭侧滑菜单。
if (isUnMoved) {
smoothClose();
//true表示拦截
if (isUserSwiped) {
if(qqInterceptFlag){
return super.onInterceptTouchEvent(ev);
public void computeScroll() {
puteScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
private void smoothExpand(){
mViewCache=MenuItem.
mScroller.startScroll(getScrollX(),0,mRightMenuWidths-getScrollX(),0);
invalidate();
private void smoothClose(){
mViewCache=
mScroller.startScroll(getScrollX(),0,-getScrollX(),0);
invalidate();
* 快速关闭。
* 用于 点击侧滑菜单上的选项,同时想让它快速关闭(删除 置顶)。
* 这个方法在ListView里是必须调用的,
* 在RecyclerView里,视情况而定,如果是mAdapter.notifyItemRemoved(pos)方法不用调用。
public void quickClose() {
if (this == mViewCache) {
mViewCache.scrollTo(0, 0);//关闭
mScroller.startScroll(0,0,0,0,0);
mViewCache =
//每次ViewDetach的时候,判断一下 ViewCache是不是自己,如果是自己,关闭侧滑菜单,且ViewCache设置为null,
// 理由:1 防止内存泄漏(ViewCache是一个静态变量)
// 2 侧滑删除后自己后,这个View被Recycler回收,复用,下一个进入屏幕的View的状态应该是普通状态,而不是展开状态。
protected void onDetachedFromWindow() {
if (this == mViewCache) {
mViewCache.smoothClose();
mViewCache =
super.onDetachedFromWindow();
//展开时,禁止长按
public boolean performLongClick() {
if (Math.abs(getScrollX()) & mTouchSlop) {
return super.performLongClick();
* @param event 向VelocityTracker添加MotionEvent
* @see VelocityTracker#obtain()
* @see VelocityTracker#addMovement(MotionEvent)
private void acquireVelocityTracker(final MotionEvent event) {
if (null == mVelocityTracker) {
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(event);
* * 释放VelocityTracker
* @see VelocityTracker#clear()
* @see VelocityTracker#recycle()
private void releaseVelocityTracker() {
if (null != mVelocityTracker) {
mVelocityTracker.clear();
mVelocityTracker.recycle();
mVelocityTracker =
一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTION_DOWN-&ACTION_MOVE-&ACTION_MOVE-&ACTION_MOVE...-&ACTION_MOVE-&ACTION_UP,Android系统中的每个View的子类都具有下面三个和TouchEvent处理密切相关的方法:
public&boolean&dispatchTouchEvent(MotionEvent&ev)&&这个方法用来分发TouchEvent
public&boolean&onInterceptTouchEvent(MotionEvent&ev)&这个方法用来拦截TouchEvent(ViewGroup才有)
public&boolean&onTouchEvent(MotionEvent&ev)&&&&&&&这个方法用来处理TouchEvent
当TouchEvent发生时,首先Activity将TouchEvent传递给最顶层的View,TouchEvent最先到达最顶层view的
dispatchTouchEvent,然后由dispatchTouchEvent方法进行分发,如果dispatchTouchEvent返回true或者false,事件均不会继续向下传递,如果down后返回false,则move和up都不会被接受,事件向上传递给Activity处理。这里为什么特别指定的down事件呢,因为如果down返回true,说明后续事件会被传递于此,被自己消费,但是move返回false呢?哈哈,这个就不会影响了,因此说down才是关键。此方法一般用于初步处理事件,因为动作是由此分发,所以通常会调用super.dispatchTouchEvent,这样就会继续调用onInterceptTouchEvent,再由onInterceptTouchEvent决定事件流向。如果interceptTouchEvent
返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。如果事件传递到某一层的子 view 的 onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent &
&也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。
下面一张图可以说明一切
里面有个重要方法在此要特别说明一下:requestDisallowInterceptTouchEvent。当检测到水平有移动距离的时候,则调用此方法,将滑动事件交给子View来处理,而ListView自身不再进行垂直滑动,否则会出现水平跟垂直滑动有冲突。
自定义item讲完了,下面就说说怎么用(终于派上用场了)
package com.binbin.slidedelmenu.
import android.content.C
import android.os.B
import android.os.PersistableB
import android.support.v7.app.AppCompatA
import android.support.v7.widget.DefaultItemA
import android.support.v7.widget.LinearLayoutM
import android.support.v7.widget.RecyclerV
import android.view.LayoutI
import android.view.V
import android.view.ViewG
import android.widget.B
import android.widget.LinearL
import android.widget.TextV
import android.widget.T
import com.binbin.slidedelmenu.DividerItemD
import com.binbin.slidedelmenu.R;
import java.util.ArrayL
import java.util.L
* Created by -- on .
public class RecyclerViewActivity extends AppCompatActivity {
private RecyclerView mRecyclerV
private List&String& str = new ArrayList&&();
private MyA
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mRecyclerView = new RecyclerView(this);
setContentView(mRecyclerView);
for (int i = 0; i & 20; i++) {
str.add(i + &个&);
//设置adapter
adapter=new MyAdapter(str,this);
mRecyclerView.setAdapter(adapter);
//设置布局管理器
LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(linearLayoutManager);
//设置Item增加、移除动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//添加分割线
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, linearLayoutManager.getOrientation(),R.drawable.divider2));
class MyAdapter extends RecyclerView.Adapter&MyAdapter.MyViewHolder& {
private List&String&
private Context mC
public MyAdapter(List&String& datas,Context mContext){
this.datas=
this.mContext=mC
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item3, parent,
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.tv.setText(datas.get(position));
holder.bt.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(RecyclerViewActivity.this,&bt========onClick&,Toast.LENGTH_SHORT).show();
holder.tv.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(RecyclerViewActivity.this,&tv========onClick&,Toast.LENGTH_SHORT).show();
holder.tvHello.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(RecyclerViewActivity.this,&hello=====onClick&,Toast.LENGTH_SHORT).show();
holder.tvDel.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(RecyclerViewActivity.this,holder.getAdapterPosition()+&del========onClick&+position,Toast.LENGTH_SHORT).show();
((MenuItem)holder.itemView).quickClose();
str.remove(holder.getAdapterPosition());
notifyItemRemoved(holder.getAdapterPosition());
notifyDataSetChanged();
holder.tv.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View v) {
Toast.makeText(RecyclerViewActivity.this,&tv==========onLongClick&,Toast.LENGTH_SHORT).show();
holder.tvHello.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View v) {
Toast.makeText(RecyclerViewActivity.this,&hello============onLongClick&,Toast.LENGTH_SHORT).show();
public int getItemCount() {
return datas.size();
class MyViewHolder extends RecyclerView.ViewHolder {
TextView tvH
TextView tvD
public MyViewHolder(View view) {
super(view);
tv = (TextView) view.findViewById(R.id.tv);
tvDel=(TextView) view.findViewById(R.id.tv_del);
tvHello=(TextView) view.findViewById(R.id.tv_hello);
bt= (Button) view.findViewById(R.id.bt);
以上就是整个项目的代码,不知道大家理解了没有,写的不好的地方,请大家多多包容与指正~~~
好了,今天的讲解到此结束,有疑问的朋友请在下面留言。
最后要感谢张旭童同学的思路,参考文章:
本文已收录于以下专栏:
相关文章推荐
在需求开发中经常会遇到需要显示圆形图片的情况,比如我们经常见到的用户圆形头像。为了实现这个效果,我们需要重新定义View,通过重写onDraw方法来使得我们的View显示成圆形。我发现主要有三种方式可...
项目中包含了一个腾讯地图,由于该mapView 不支持圆角背景,so决定自己画四个圆角view,覆盖在mapView上以实现圆角矩形的效果。public class CornerView extend...
本文转载自:http://blog.csdn.net/binbinqq86/article/details/项目用到了ListView的侧滑删除的功能,由于当时项目比较赶,就随便在网上...
在最近的项目中,我的ListView中item选项是长按删除的效果(Android的通常做法长按或点击),老板觉得这个效果不好,提出要求做类似QQ消息列表横向滑动时删除消息的效果。
本博文实现思路是...
转载自:http://blog.csdn.net/lmj/article/details/【张鸿洋的博客】
看到QQ的侧滑菜单的效果,感觉真的很酷炫,想找一些高...
小编在与同事们研究侧滑菜单的时候
百度搜索了很多例子
差不多都是一个人的项目
研究了好久
差点崩溃--------...
首先,来说说前面实现的普通侧滑菜单与接下来要实现的抽屉式菜单的区别:
普通菜单:在显示菜单的时候,会随着内容一起移动。
抽屉式菜单:菜单仿佛是内容区域底下,就像开关抽屉一样,比如有两层抽屉,下面的...
原创博客地址:点击传送
AndroidResideMenu
github:/SpecialCyCi/AndroidResideMenu
csdn:http:/...
他的最新文章
讲师:钟钦成
讲师:宋宝华
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 怎么才能知道照片像素 的文章

 

随机推荐