下拉刷新对于一个app来说是必不可少的一个功能,在早期大多数使用的是chrisbanes的PullToRefresh,或是修改自该框架的其他库。而到现在已经有了更多的选择,github上还是有很多体验不错的下拉刷新。
创新互联公司长期为千余家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为卓资企业提供专业的成都网站建设、成都做网站,卓资网站改版等技术服务。拥有10年丰富建站经验和众多成功案例,为您定制开发。
而下拉刷新主要有两种实现方式:
1.
在ListView中添加header和footer,监听ListView的滑动事件,动态设置header/footer的高度,但是这种方式只适用于ListView,RecyclerView。
2.
第二种方式则是继承ViewGroup或其子类,监听事件,通过scroll或Layout的方式移动child。如图(又分两种情况)
Layout时将header放到屏幕外面,target则填充满屏幕。这个也是SwipeRefreshLayout的实现原理(第二种,只下拉header)
这两种(指的是继承ListView或继承ViewGroup)下拉刷新的实现方式主要有以下区别
继承ListView/RecyclerView
继承ViewGroup或其子类
适用范围
ListView/Recycler
理论支持所有View和ViewGroup
加载更多
实现简单,体验好
可以实现,看需求了,做不出ListView那种加载效果的,体验比较一般
多点触控
可以完美支持
header下拉状态中是完美支持的,但是回去之后,很难将多点触控事件传递给child
案例
QQ好友列表
美团、京东等
而今天,我打算先讲第二种方式实现方式,继承ViewGroup,代码可以直接参考SwipeRefreshLayout,或者pullToRefresh,或者ultra-pull-to-refresh
一、思考和需求
下拉刷新需要几个状态:Reset–
Pull
–
Refreshing
–
Completed
–Reset
为了应对各式各样的下拉刷新设计,我们应该提供设置自定义的Header,开发者可以通过实现接口从而自定义自己的header。
而且header可以有两种显示方式,一种是只下拉header,另外一种则是header和target一起下拉。
二、着手实现代码
一、概述
Android中的有个原生的下拉列表控件Spinner,但是这个控件有时候不符合我们自己的要求,
比如有时候我们需要类似windows 或者web网页中常见的那种下拉列表控件,类似下图这样的:
这个时候只有自己动手写一个了。其实实现起来不算很难,
本文实现的方案是采用TextView +ImageView+PopupWindow的组合方案。
先来看看我们的自己写的控件效果图吧:(源码在文章下面最后给出哈!)
二、自定义下拉列表框控件的实现
1. 自定义控件用到的布局文件和资源:
结果框的布局页面:dropdownlist_view.xml:
?xml version="1.0" encoding="utf-8"?
RelativeLayout xmlns:android=""
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:id="@+id/compound"
android:background="@drawable/dropdown_bg_selector"
TextView
android:id="@+id/text"
android:layout_width="250dp"
android:layout_height="40dp"
android:paddingLeft="10dp"
android:text="文本文字"
android:gravity="center_vertical"
android:textSize="14sp"
android:padding="5dp"
android:singleLine="true" /
ImageView
android:id="@+id/btn"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_toRightOf="@+id/text"
android:src="@drawable/dropdown"
android:padding="5dp"
android:layout_centerVertical="true"
android:gravity="center"/
/RelativeLayout
下拉弹窗列表布局页面:dropdownlist_popupwindow.xml:
?xml version="1.0" encoding="utf-8"?
LinearLayout xmlns:android=""
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
ListView
android:id="@+id/listView"
android:layout_width="280dp"
android:layout_height="wrap_content"
android:divider="#666666"
android:dividerHeight="1dp"
/ListView
/LinearLayout
selector资源文件:
dropdown_list_selector.xml:
?xml version="1.0" encoding="utf-8"?
selector xmlns:android=""
item android:state_pressed="true" android:drawable="@color/dropdownlist_item_press"/
item android:drawable="@color/dropdownlist_item"/
/selector
dropdown_bg_selector.xml:
?xml version="1.0" encoding="utf-8"?
selector xmlns:android=""
item android:state_pressed="true" android:drawable="@color/dropdownlist_press"/
item android:drawable="@color/dropdownlist_bg"/
/selector
2. 自定义下拉列表框控件类的实现:
我们采用了TextView+ImageView+PopupWindow的组合方案,所以我的自定义控件需要重写ViewGroup,由于我们已经知道了,布局方向为竖直方向,所以这里,
我直接继承LinearLayout来写这个控件。具体实现代码如下:
package com.czm.xcdropdownlistview;
import java.util.ArrayList;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;
@SuppressLint("NewApi")
/**
* 下拉列表框控件
* @author caizhiming
*
*/
public class XCDropDownListView extends LinearLayout{
private TextView editText;
private ImageView imageView;
private PopupWindow popupWindow = null;
private ArrayListString dataList = new ArrayListString();
private View mView;
public XCDropDownListView(Context context) {
this(context,null);
// TODO Auto-generated constructor stub
}
public XCDropDownListView(Context context, AttributeSet attrs) {
this(context, attrs,0);
// TODO Auto-generated constructor stub
}
public XCDropDownListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
initView();
}
public void initView(){
String infServie = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater layoutInflater;
layoutInflater = (LayoutInflater) getContext().getSystemService(infServie);
View view = layoutInflater.inflate(R.layout.dropdownlist_view, this,true);
editText= (TextView)findViewById(R.id.text);
imageView = (ImageView)findViewById(R.id.btn);
this.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(popupWindow == null ){
showPopWindow();
}else{
closePopWindow();
}
}
});
}
/**
* 打开下拉列表弹窗
*/
private void showPopWindow() {
// 加载popupWindow的布局文件
String infServie = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater layoutInflater;
layoutInflater = (LayoutInflater) getContext().getSystemService(infServie);
View contentView = layoutInflater.inflate(R.layout.dropdownlist_popupwindow, null,false);
ListView listView = (ListView)contentView.findViewById(R.id.listView);
listView.setAdapter(new XCDropDownListAdapter(getContext(), dataList));
popupWindow = new PopupWindow(contentView,LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
popupWindow.setBackgroundDrawable(getResources().getDrawable(R.color.transparent));
popupWindow.setOutsideTouchable(true);
popupWindow.showAsDropDown(this);
}
/**
* 关闭下拉列表弹窗
*/
private void closePopWindow(){
popupWindow.dismiss();
popupWindow = null;
}
/**
* 设置数据
* @param list
*/
public void setItemsData(ArrayListString list){
dataList = list;
editText.setText(list.get(0).toString());
}
/**
* 数据适配器
* @author caizhiming
*
*/
class XCDropDownListAdapter extends BaseAdapter{
Context mContext;
ArrayListString mData;
LayoutInflater inflater;
public XCDropDownListAdapter(Context ctx,ArrayListString data){
mContext = ctx;
mData = data;
inflater = LayoutInflater.from(mContext);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mData.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
// 自定义视图
ListItemView listItemView = null;
if (convertView == null) {
// 获取list_item布局文件的视图
convertView = inflater.inflate(R.layout.dropdown_list_item, null);
listItemView = new ListItemView();
// 获取控件对象
listItemView.tv = (TextView) convertView
.findViewById(R.id.tv);
listItemView.layout = (LinearLayout) convertView.findViewById(R.id.layout_container);
// 设置控件集到convertView
convertView.setTag(listItemView);
} else {
listItemView = (ListItemView) convertView.getTag();
}
// 设置数据
listItemView.tv.setText(mData.get(position).toString());
final String text = mData.get(position).toString();
listItemView.layout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
editText.setText(text);
closePopWindow();
}
});
return convertView;
}
}
private static class ListItemView{
TextView tv;
LinearLayout layout;
}
}
三、如何使用该自定义下拉列表框控件
使用该控件和使用普通的自带的控件一样,首先需要在布局文件中引用该控件:
RelativeLayout xmlns:android=""
xmlns:tools=""
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.czm.xcdropdownlistview.MainActivity"
tools:ignore="MergeRootFrame"
com.czm.xcdropdownlistview.XCDropDownListView
android:id="@+id/drop_down_list_view"
android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true" /
/RelativeLayout
其次,就是在代码中使用该控件:
package com.czm.xcdropdownlistview;
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
/**
* 使用下拉列表框控件 示例
* @author caizhiming
*
*/
public class MainActivity extends Activity {
XCDropDownListView dropDownListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dropDownListView = (XCDropDownListView)findViewById(R.id.drop_down_list_view);
ArrayListString list = new ArrayListString();
for(int i = 0;i 6;i++){
list.add("下拉列表项"+(i+1));
}
dropDownListView.setItemsData(list);
}
}
对了,这个控件中,我没有实现点击item项回调接口,这个可能对有些写惯了回调的可能觉得少了写什么的感觉,有兴趣的你可以自己添加相关回调操作哈,这个大家应该都会把。
Android的下拉列表是用Spinner 这个类来实现的。
Spinner的使用(分别使用ArrayAdapter和自定义Adapter实现),使用ArrayAdapter进行适配数据:
1:首先定义一个布局文件:
LinearLayout xmlns:android=""
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
Spinner
android:id="@+id/spinner1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/
/LinearLayout
2:建立数据源,使用数组,这些数据将会在Spinner下来列表中进行显示:
?xml version="1.0" encoding="utf-8"?
resources
string-array name="spinnername"
item北京/item
item上海 /item
item广州/item
item深圳/item
/string-array
/resources
3:接着在Activity中加入如下的代码(使用了系统定义的下拉列表的布局文件,当然也可以自定义)
// 初始化控件
mSpinner = (Spinner) findViewById(R.id.spinner1);
// 建立数据源
String[] mItems = getResources().getStringArray(R.array.spinnername);
// 建立Adapter并且绑定数据源
ArrayAdapterString _Adapter=new ArrayAdapterString(this,android.R.layout.simple_spinner_item, mItems);
//绑定 Adapter到控件
mSpinner.setAdapter(_Adapter);
在UI中经常会使用到下拉列表,在android控件中有两个下拉列表控件:
在xml中添加控件的使用:
主题:
这些都没有达到我要的效果:
android:entries // 传入的是values文件夹下的arrayx.xml内的数据
android:spinnerMode //显示模式有popmenu和dialog两种
android:prompt //当显示模式为dialog时生效,作用为显示dialog的标题内容
AutoCompleteTextview 是用来做输入过虑用的,在Android中,下拉列表应该使用Spinner这个才是下拉选择控件。
设置spinner下拉菜单的宽度可在布局文件中添加如下语句:
android:dropDownWidth="100dp"
其中,100dp就是下拉菜单的宽度值,单位为像素。
Spinner控件是一种列表类型的控件,它的继承关系如下:
java.lang.Object
↳ android.view.View
↳ android.view.ViewGroup
↳ android.widget.AdapterViewTextends android.widget.Adapter
↳ android.widget.AbsSpinner
↳ android.widget.Spinner
android.widget.Spinner继承了android.view.ViewGroup类。