当前位置: 移动技术网 > 移动技术>移动开发>Android > Android UI仿QQ好友列表分组悬浮效果

Android UI仿QQ好友列表分组悬浮效果

2019年07月24日  | 移动技术网移动技术  | 我要评论

本文实例为大家分享了android ui仿qq好友列表分组悬浮效果的具体代码,供大家参考,具体内容如下



楼主是在平板上測试的。图片略微有点大,大家看看效果就好

接下来贴源代码:

pinnedheaderexpandablelistview.java
要注意的是 在 ongroupclick方法中parent.setselectedgroup(groupposition)这句代码的作用是点击分组置顶,

我这边不须要这个效果。qq也没实用到,所以给凝视了。大家假设须要能够解开凝视

package com.xiaos.view;

import android.content.context;
import android.graphics.canvas;
import android.util.attributeset;
import android.view.motionevent;
import android.view.view;
import android.view.viewgroup;
import android.widget.abslistview;
import android.widget.abslistview.onscrolllistener;
import android.widget.expandablelistadapter;
import android.widget.expandablelistview;
import android.widget.expandablelistview.ongroupclicklistener;

public class pinnedheaderexpandablelistview extends expandablelistview implements onscrolllistener,ongroupclicklistener {
 public pinnedheaderexpandablelistview(context context, attributeset attrs, int defstyle) {
 super(context, attrs, defstyle);
 registerlistener();
 }

 public pinnedheaderexpandablelistview(context context, attributeset attrs) {
 super(context, attrs);
 registerlistener();
 }

 public pinnedheaderexpandablelistview(context context) {
 super(context);
 registerlistener();
 }

 /**
 * adapter 接口 . 列表必须实现此接口 .
 */
 public interface headeradapter {
 public static final int pinned_header_gone = 0;
 public static final int pinned_header_visible = 1;
 public static final int pinned_header_pushed_up = 2;
 
 /**
  * 获取 header 的状态
  * @param groupposition
  * @param childposition
  * @return pinned_header_gone,pinned_header_visible,pinned_header_pushed_up 当中之中的一个
  */
 int getheaderstate(int groupposition, int childposition);

 /**
  * 配置 header, 让 header 知道显示的内容
  * @param header
  * @param groupposition
  * @param childposition
  * @param alpha
  */
 void configureheader(view header, int groupposition,int childposition, int alpha);

 /**
  * 设置组按下的状态 
  * @param groupposition
  * @param status
  */
 void setgroupclickstatus(int groupposition, int status);

 /**
  * 获取组按下的状态
  * @param groupposition
  * @return
  */
 int getgroupclickstatus(int groupposition);

 }

 private static final int max_alpha = 255;

 private headeradapter madapter;

 /**
 * 用于在列表头显示的 view,mheaderviewvisible 为 true 才可见
 */
 private view mheaderview;

 /**
 * 列表头是否可见
 */
 private boolean mheaderviewvisible;

 private int mheaderviewwidth;

 private int mheaderviewheight;

 public void setheaderview(view view) {
 mheaderview = view;
 abslistview.layoutparams lp = new abslistview.layoutparams(
 viewgroup.layoutparams.match_parent, viewgroup.layoutparams.wrap_content);
 view.setlayoutparams(lp);

 if (mheaderview != null) {
  setfadingedgelength(0);
 }

 requestlayout();
 }

 private void registerlistener() {
 setonscrolllistener(this);
 setongroupclicklistener(this);
 }

 /**
 * 点击 headerview 触发的事件
 */
 private void headerviewclick() {
 long packedposition = getexpandablelistposition(this.getfirstvisibleposition());
 
 int groupposition = expandablelistview.getpackedpositiongroup(packedposition);
 
 if (madapter.getgroupclickstatus(groupposition) == 1) {
  this.collapsegroup(groupposition);
  madapter.setgroupclickstatus(groupposition, 0);
 }
 else{
  this.expandgroup(groupposition);
  madapter.setgroupclickstatus(groupposition, 1);
 }
 
 this.setselectedgroup(groupposition);
 }

 private float mdownx;
 private float mdowny;

 /**
 * 假设 headerview 是可见的 , 此函数用于推断是否点击了 headerview, 并对做对应的处理 ,
 * 由于 headerview 是画上去的 , 所以设置事件监听是无效的 , 仅仅有自行控制 .
 */
 @override
 public boolean ontouchevent(motionevent ev) {
 if (mheaderviewvisible) {
  switch (ev.getaction()) {
  case motionevent.action_down:
  mdownx = ev.getx();
  mdowny = ev.gety();
  if (mdownx <= mheaderviewwidth && mdowny <= mheaderviewheight) {
   return true;
  }
  break;
  case motionevent.action_up:
  float x = ev.getx();
  float y = ev.gety();
  float offsetx = math.abs(x - mdownx);
  float offsety = math.abs(y - mdowny);
  // 假设 headerview 是可见的 , 点击在 headerview 内 , 那么触发 headerclick()
  if (x <= mheaderviewwidth && y <= mheaderviewheight
  && offsetx <= mheaderviewwidth && offsety <= mheaderviewheight) {
   if (mheaderview != null) {
   headerviewclick();
   }

   return true;
  }
  break;
  default:
  break;
  }
 }

 return super.ontouchevent(ev);

 }

 @override
 public void setadapter(expandablelistadapter adapter) {
 super.setadapter(adapter);
 madapter = (headeradapter) adapter;
 }

 /**
 * 
 * 点击了 group 触发的事件 , 要依据依据当前点击 group 的状态来
 */
 @override
 public boolean ongroupclick(expandablelistview parent,view v,int groupposition,long id) {
 if (madapter.getgroupclickstatus(groupposition) == 0) {
  madapter.setgroupclickstatus(groupposition, 1);
  parent.expandgroup(groupposition);
  //header自己主动置顶
  //parent.setselectedgroup(groupposition);
  
 } else if (madapter.getgroupclickstatus(groupposition) == 1) {
  madapter.setgroupclickstatus(groupposition, 0);
  parent.collapsegroup(groupposition);
 }

 // 返回 true 才干够弹回第一行 , 不知道为什么
 return true;
 }

 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
 super.onmeasure(widthmeasurespec, heightmeasurespec);
 if (mheaderview != null) {
  measurechild(mheaderview, widthmeasurespec, heightmeasurespec);
  mheaderviewwidth = mheaderview.getmeasuredwidth();
  mheaderviewheight = mheaderview.getmeasuredheight();
 }
 }

 private int moldstate = -1;

 @override
 protected void onlayout(boolean changed, int left, int top, int right,int bottom) {
 super.onlayout(changed, left, top, right, bottom);
 final long flatpostion = getexpandablelistposition(getfirstvisibleposition());
 final int grouppos = expandablelistview.getpackedpositiongroup(flatpostion);
 final int childpos = expandablelistview.getpackedpositionchild(flatpostion);
 int state = madapter.getheaderstate(grouppos, childpos);
 if (mheaderview != null && madapter != null && state != moldstate) {
  moldstate = state;
  mheaderview.layout(0, 0, mheaderviewwidth, mheaderviewheight);
 }

 configureheaderview(grouppos, childpos);
 }

 public void configureheaderview(int groupposition, int childposition) {
 if (mheaderview == null || madapter == null
 || ((expandablelistadapter) madapter).getgroupcount() == 0) {
  return;
 }

 int state = madapter.getheaderstate(groupposition, childposition);

 switch (state) {
  case headeradapter.pinned_header_gone: {
  mheaderviewvisible = false;
  break;
  }
 
  case headeradapter.pinned_header_visible: {
  madapter.configureheader(mheaderview, groupposition,childposition, max_alpha);
 
  if (mheaderview.gettop() != 0){
   mheaderview.layout(0, 0, mheaderviewwidth, mheaderviewheight);
  }
 
  mheaderviewvisible = true;
 
  break;
  }
 
  case headeradapter.pinned_header_pushed_up: {
  view firstview = getchildat(0);
  int bottom = firstview.getbottom();
 
  // intitemheight = firstview.getheight();
  int headerheight = mheaderview.getheight();
 
  int y;
 
  int alpha;
 
  if (bottom < headerheight) {
   y = (bottom - headerheight);
   alpha = max_alpha * (headerheight + y) / headerheight;
  } else {
   y = 0;
   alpha = max_alpha;
  }
  
  madapter.configureheader(mheaderview, groupposition,childposition, alpha);
 
  if (mheaderview.gettop() != y) {
   mheaderview.layout(0, y, mheaderviewwidth, mheaderviewheight + y);
  }
 
  mheaderviewvisible = true;
  break;
  }
 }
 }

 @override
 /**
 * 列表界面更新时调用该方法(如滚动时)
 */
 protected void dispatchdraw(canvas canvas) {
 super.dispatchdraw(canvas);
 if (mheaderviewvisible) {
  //分组栏是直接绘制到界面中。而不是增加到viewgroup中
  drawchild(canvas, mheaderview, getdrawingtime());
 }
 }

 @override
 public void onscroll(abslistview view, int firstvisibleitem,int visibleitemcount, int totalitemcount) {
 final long flatpos = getexpandablelistposition(firstvisibleitem);
 int groupposition = expandablelistview.getpackedpositiongroup(flatpos);
 int childposition = expandablelistview.getpackedpositionchild(flatpos);
 
 configureheaderview(groupposition, childposition);
 }

 @override
 public void onscrollstatechanged(abslistview view, int scrollstate) {
 }
}

pinnedheaderexpandableadapter.java 适配器

实现了pinnedheaderexpandablelistview中headeradapter接口

package com.xiaos.adapter;

import android.content.context;
import android.util.sparseintarray;
import android.view.layoutinflater;
import android.view.view;
import android.view.viewgroup;
import android.widget.baseexpandablelistadapter;
import android.widget.imageview;
import android.widget.textview;

import com.xiaos.pinnedheaderexpandable.r;
import com.xiaos.view.pinnedheaderexpandablelistview;
import com.xiaos.view.pinnedheaderexpandablelistview.headeradapter;

public class pinnedheaderexpandableadapter extends baseexpandablelistadapter implements headeradapter{
private string[][] childrendata;
private string[] groupdata;
private context context;
private pinnedheaderexpandablelistview listview;
private layoutinflater inflater;

public pinnedheaderexpandableadapter(string[][] childrendata,string[] groupdata
,context context,pinnedheaderexpandablelistview listview){
this.groupdata = groupdata; 
this.childrendata = childrendata;
this.context = context;
this.listview = listview;
inflater = layoutinflater.from(this.context);
}

@override
public object getchild(int groupposition, int childposition) {
return childrendata[groupposition][childposition];
}

@override
public long getchildid(int groupposition, int childposition) {
return 0;
}

@override
public view getchildview(int groupposition, int childposition,
boolean islastchild, view convertview, viewgroup parent) {
view view = null; 
if (convertview != null) { 
view = convertview; 
} else { 
view = createchildrenview(); 
} 
textview text = (textview)view.findviewbyid(r.id.childto);
text.settext(childrendata[groupposition][childposition]); 
return view; 
}

@override
public int getchildrencount(int groupposition) {
return childrendata[groupposition].length;
}

@override
public object getgroup(int groupposition) {
return groupdata[groupposition];
}

@override
public int getgroupcount() {
return groupdata.length;
}

@override
public long getgroupid(int groupposition) {
return 0;
}

@override
public view getgroupview(int groupposition, boolean isexpanded,
view convertview, viewgroup parent) {
view view = null; 
if (convertview != null) { 
view = convertview; 
} else { 
view = creategroupview(); 
}

imageview iv = (imageview)view.findviewbyid(r.id.groupicon);

if (isexpanded) {
iv.setimageresource(r.drawable.btn_browser2);
}
else{
iv.setimageresource(r.drawable.btn_browser);
}

textview text = (textview)view.findviewbyid(r.id.groupto);
text.settext(groupdata[groupposition]); 
return view; 
}

@override
public boolean hasstableids() {
return true;
}

@override
public boolean ischildselectable(int groupposition, int childposition) {
return true;
}

private view createchildrenview() {
return inflater.inflate(r.layout.child, null);
}

private view creategroupview() {
return inflater.inflate(r.layout.group, null);
}

@override
public int getheaderstate(int groupposition, int childposition) {
final int childcount = getchildrencount(groupposition);
if (childposition == childcount - 1) {
return pinned_header_pushed_up;
} else if (childposition == -1
&& !listview.isgroupexpanded(groupposition)) {
return pinned_header_gone;
} else {
return pinned_header_visible;
}
}

@override
public void configureheader(view header, int groupposition,
int childposition, int alpha) {
string groupdata = this.groupdata[groupposition];
((textview) header.findviewbyid(r.id.groupto)).settext(groupdata);

}

private sparseintarray groupstatusmap = new sparseintarray();

@override
public void setgroupclickstatus(int groupposition, int status) {
groupstatusmap.put(groupposition, status);
}

@override
public int getgroupclickstatus(int groupposition) {
if (groupstatusmap.keyat(groupposition)>=0) {
return groupstatusmap.get(groupposition);
} else {
return 0;
}
}
}

mainactivity.java主activity

package com.xiaos.pinnedheaderexpandable;

import android.app.activity;
import android.os.bundle;
import android.view.view;
import android.widget.expandablelistview;
import android.widget.expandablelistview.ongroupclicklistener;

import com.xiaos.adapter.pinnedheaderexpandableadapter;
import com.xiaos.view.pinnedheaderexpandablelistview;

public class mainactivity extends activity{
 private pinnedheaderexpandablelistview explistview;
 private string[][] childrendata = new string[10][10];
 private string[] groupdata = new string[10];
 private int expandflag = -1;//控制列表的展开 
 private pinnedheaderexpandableadapter adapter;
 
 
 @override
 protected void oncreate(bundle savedinstancestate) {
 super.oncreate(savedinstancestate);
 setcontentview(r.layout.layout_main);
 initview();
 initdata();
 }
 
 /**
 * 初始化view
 */
 private void initview() {
 explistview = (pinnedheaderexpandablelistview)findviewbyid(r.id.explistview);
 }

 /**
 * 初始化数据
 */
 private void initdata() {
 for(int i=0;i<10;i++){
  groupdata[i] = "分组"+i;
 }
 
 for(int i=0;i<10;i++){
  for(int j=0;j<10;j++){
  childrendata[i][j] = "好友"+i+"-"+j;
  }
 }
 //设置悬浮头部view
 explistview.setheaderview(getlayoutinflater().inflate(r.layout.group_head,
  explistview, false));
 adapter = new pinnedheaderexpandableadapter(childrendata, groupdata, getapplicationcontext(),explistview);
 explistview.setadapter(adapter);
 
 //设置单个分组展开
 //explistview.setongroupclicklistener(new groupclicklistener());
 }
 
 class groupclicklistener implements ongroupclicklistener{
 @override
 public boolean ongroupclick(expandablelistview parent, view v,
  int groupposition, long id) {
  if (expandflag == -1) {
  // 展开被选的group
  explistview.expandgroup(groupposition);
  // 设置被选中的group置于顶端
  explistview.setselectedgroup(groupposition);
  expandflag = groupposition;
  } else if (expandflag == groupposition) {
  explistview.collapsegroup(expandflag);
  expandflag = -1;
  } else {
  explistview.collapsegroup(expandflag);
  // 展开被选的group
  explistview.expandgroup(groupposition);
  // 设置被选中的group置于顶端
  explistview.setselectedgroup(groupposition);
  expandflag = groupposition;
  }
  return true;
 }
 }
}

布局文件

child.xml

<?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="40dip"
  android:background="#ffffff" >

  <imageview
    android:id="@+id/groupicon"
    android:layout_width="40dp"
    android:layout_height="40dp"
    android:paddingleft="10dp"
    android:src="@null" />

  <textview
    android:id="@+id/childto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingleft="10dp"
    android:paddingtop="10dip"
    android:textcolor="#000000"
    android:textsize="16sp" />

</linearlayout>

group_head.xml

<?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="wrap_content"
  android:orientation="horizontal" 
  android:background="#b8e6fa"
  android:gravity="center_vertical">
  <imageview 
    android:id="@+id/groupicon"
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:contentdescription="@null"
    android:layout_marginleft="10dp"
    android:src="@drawable/btn_browser2"/>
  <textview
    android:id="@+id/groupto"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:textcolor="#000000"
    android:textsize="18sp" 
    android:gravity="center_vertical|left"/>

</linearlayout>

group.xml

<?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="wrap_content"
  android:orientation="horizontal" 
  android:background="#b8e6fa"
  android:gravity="center_vertical">
  <imageview 
    android:id="@+id/groupicon"
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:contentdescription="@null"
    android:layout_marginleft="10dp"
    android:src="@drawable/btn_browser"/>
  <textview
    android:id="@+id/groupto"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:textcolor="#000000"
    android:textsize="18sp" 
    android:gravity="center_vertical|left"/>
</linearlayout>

layout_main.xml

<?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="#f0f0f0"
  android:orientation="vertical" >

  <com.xiaos.view.pinnedheaderexpandablelistview
    android:id="@+id/explistview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginleft="0.0dip"
    android:cachecolorhint="#00000000"
    android:choicemode="singlechoice"
    android:drawselectorontop="false"
    android:fastscrollenabled="false"
    android:footerdividersenabled="true"
    android:groupindicator="@null"
    android:scrollbars="vertical"
    android:scrollingcache="true" />

</linearlayout>

androidmanifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.xiaos.pinnedheaderexpandable"
  android:versioncode="1"
  android:versionname="1.0" >

  <uses-sdk
    android:minsdkversion="8"
    android:targetsdkversion="19" />

  <application
    android:allowbackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/apptheme" >
    <activity 
      android:name=".mainactivity"
      android:icon="@drawable/ic_launcher">
      <intent-filter>
        <action android:name="android.intent.action.main"/>
        <category android:name="android.intent.category.launcher"/>
      </intent-filter>
    </activity>
  </application>

</manifest>

两张图片:


下载地址:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网