android测试 掘金,仿掘金框架之listview全解(一)

1460000006788254

文章首发:Android程序员日记

作者:贤榆的鱼

测试阅读时间:8min

前言

有有很长一段时间没有更新了,这次给大家带来了一个框架Demo——仿掘金App,希望可以通过这个Demo和大家分享一些控件的实际使用!这次呢先给大家带来了自动隐藏布局且带下拉加载更多的listView!大家可以先看看掘金app的效果图,后面我们把自己的放上来比较一下。

今天先放静态的,明天放一张动的!

1460000006788255

正文

通过仿掘金框架的这个listView大家可以练习到一下几个方面:

[1] listView的基本用法

[2] listView的viewHolder的复用优化及多条目

[3] listview添加headerView实现一些布局和功能

[4] listview通过footerview和滚动监听实现上拉加载更多

[5] listview通过触摸监听事件实现上下bar的布局隐藏功能

[ 1 ] listView的基本用法

首先在xml文件中配置listview

android:scrollbars="none"

android:id="@+id/listView"

android:fadingEdge="vertical"

android:overScrollMode="never"

android:dividerHeight="0.5dp"

android:divider="#05999999"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_alignParentTop="true" />

上面用到的属性:

android:overScrollMode="never" ——滚动越界的模式:ifcontentscroll和always才会有越界效果!

android:dividerHeight="0.5dp" —— listview item之间间隔的高度

android:divider="#05999999" —— listview item之间间隔的背景或者颜色

android:fadingEdge="vertical" —— 上边和下边有黑色的阴影 值为none的话就没有阴影

android:scrollbars="none" —— 值为horizontal|vertical的时候,会自动隐藏和显示相应的滚动条,值为none时隐藏滚动条。

部分常用属性补充:

android:cacheColorHint="#00000000" —— 设置拖动背景色为透明

android:fastScrollEnabled="true" —— 快速滚动效果属性配置,在快速滚动的时候旁边会出现一个小方块的快速滚动效果,自动隐藏和显示,

android:scrollbarTrackVertical="@color/colorAccent" —— 设置滚动条的背景色,只能设置引用不能直接填写“#ffffff”

android:scrollbarThumbVertical="@color/colorPrimaryDark" —— 设置滚动条游标的背景色,这里只能引用不能直接填写“#ffffff”

android:scrollbarStyle="outsideInset" —— 四个值的含义如下

outsideInset : 该ScrollBar显示在视图(view)的边缘,增加了view的padding. 如果可能的话,该ScrollBar仅仅覆盖这个view的背景.

outsideOverlay : 该ScrollBar显示在视图(view)的边缘,不增加view的padding,该ScrollBar将被半透明覆盖

insideInset :该ScrollBar显示在padding区域里面,增加了控件的padding区域,该ScrollBar不会和视图的内容重叠.

insideOverlay : 该ScrollBar显示在内容区域里面,不会增加了控件的padding区域,该ScrollBar以半透明的样式覆盖在视图(view)的内容上.

android:footerDividersEnabled —— 当设为false时,ListView将不会在各个footer之间绘制divider.默认为true。

android:headerDividersEnabled —— 当设为false时,ListView将不会在各个header之间绘制divider.默认为true。

[ 2 ] ListView的复用优化及多条目

1460000006788256

在activity中初始化listview并给他设置adapter

mlistView = (ListView) findViewById(R.id.listView);

mAdapter = new ViewHolderAdapter(this, mDates);

mlistView.setAdapter(mAdapter);

在adapter当中利用viewholder模式对listView的复用机制进行优化,在滑动的时候会更加的顺畅。以及listview多条目的使用它。通过viewholder内部类以item布局中的控件最为变量,可以有效的避免每次都通过findViewById()来实例化控件,从而达到复用控件实例,优化listview的目的!

而这里用到的多条目一般情况下是为增加listview条目的多样样行,让listview表现的更加丰富!当然还有一个情况就是为了突出数据的结构分层!我们这里就是为了凸显结构,加了一个文章分类title!

public class ViewHolderAdapter extends BaseAdapter {

private final Context mContext;

private List mDates=new ArrayList<>();

private static final int TITLE=0;

private static final int CONTENT=1;

public ViewHolderAdapter(Context mcontext, List newsItems) {

this.mContext=mcontext;

//添加分类的标题

mDates.add(new NewsItem("热门文章"));

mDates.addAll(1,newsItems);

}

@Override

public int getItemViewType(int position) {

if(position==0){//position为0是itemType为分类Title

return TITLE;

}else{

return CONTENT;

}

}

//返回listview条目类型的总数,我们这只有文章和分类title两种!

@Override

public int getViewTypeCount() {

return 2;

}

//返回listview中的条目数据总数

@Override

public int getCount() {

return mDates==null?0:mDates.size();

}

//返回条目位置对应的内容

@Override

public NewsItem getItem(int position) {

return mDates.get(position);

}

@Override

public long getItemId(int position) {

return position;

}

//在getView当中对多条目的条目类型进行区分并分别做处理!

@Override

public View getView(int position, View convertView, ViewGroup parent) {

NewsItem item = getItem(position);

ContentViewHolder contentViewHolder;

TieleViewHolder tieleViewHolder;

int type = getItemViewType(position);

if(convertView==null){

switch (type){

case TITLE:

tieleViewHolder=new TieleViewHolder();

convertView=View.inflate(mContext,R.layout.lv_item_title,null);

tieleViewHolder.tv_title= (TextView) convertView.findViewById(R.id.tv_top_title);

tieleViewHolder.tv_title.setText(item.getTitle());

//绑定一个viewHolder方便在对convertView复用时也对viewHolder进行复用

convertView.setTag(tieleViewHolder);

break;

case CONTENT:

contentViewHolder=new ContentViewHolder();

convertView=View.inflate(mContext,R.layout.lv_item,null);

contentViewHolder.iamge= (ImageView) convertView.findViewById(R.id.iv_image);

contentViewHolder.tv_articleInfo= (TextView) convertView.findViewById(R.id.tv_info);

contentViewHolder.tv_title= (TextView) convertView.findViewById(R.id.tv_title);

contentViewHolder.iamge.setImageResource(item.getImage());

contentViewHolder.tv_title.setText(item.getTitle());

contentViewHolder.tv_articleInfo.setText(item.getArtcileInfo());

convertView.setTag(contentViewHolder);

break;

}

}else{

switch (type){

case TITLE:

tieleViewHolder= (TieleViewHolder) convertView.getTag();

tieleViewHolder.tv_title.setText(item.getTitle());

break;

case CONTENT:

//复用绑定的ViewHolder

contentViewHolder= (ContentViewHolder) convertView.getTag();

contentViewHolder.iamge.setImageResource(item.getImage());

contentViewHolder.tv_title.setText(item.getTitle());

contentViewHolder.tv_articleInfo.setText(item.getArtcileInfo());

}

}

return convertView;

}

public void addDate(List newsItems, boolean isHead) {

if(mDates==null){

this.mDates =newsItems;

}else{

if (isHead){

mDates.addAll(1,newsItems);

}else{

mDates.addAll(getCount(),newsItems);

}

}

}

//创建两个不同itemType对应的ViewHolder内部类

public class ContentViewHolder {

ImageView iamge;

TextView tv_title;

TextView tv_articleInfo;

}

public class TieleViewHolder {

TextView tv_title;

}

}

[ 3 ] ListView添加HeaderView

ListView通过添加HeaderView其实可以实现很多的效果,比如下拉刷新的动画就可以放在HeadView当中。当然这次仿掘金的app用了SwipeRefreshLayout实现了下拉刷新,后面会针对这个写一篇的大家也别急!而这个app中依然也用到了headerView。这里是添加了一个头布局。如下图:

1460000006788257

我们在[ 2 ] 的初始化listview代码之后设置adapter之前加上添加headerView的代码

header = LayoutInflater.from(this).inflate(R.layout.lv_headerview, mlistView, false);

//header = getLayoutInflater().inflate(R.layout.lv_headerview,null,true);

//header=View.inflate(this,R.layout.lv_headerview,null);

mlistView.addHeaderView(header);

注 :

关于lv_headerview.xml的代码大家可以在文末的github地址中获取到,这里就不贴出来了!不过上面代码中也有要注意的地方,我写了三种方式实例化headerView!第一种和第二种是一样!而第三种方法省去了第三个参数!

大家在实例化的时候需要注意的是,如果你的headerview有预留的一段空隙,像我的不居中的一样,那么你的第二个参数需要填写listview的实例对象,而第三个参数需要填写false!否则heaaderview下面的空白就会消失(上面的第二、三个方法就会有该现象)!还有一个就第二个参数填写了listview实例,而第三个对象填写了true!这个时候,就会报错崩溃报如下错误:

Caused by: java.lang.UnsupportedOperationException: addView(View, LayoutParams) is not supported in AdapterView

[ 4 ] 通过footerview和滚动监听实现上拉加载更多

1460000006788258

思路:

Step1:先加载一个带加载标示的footerview

Step2:实现listview的滚动监听事件

Step3:判断是否为最后一个条目?是,就显示footerview并且异步加载数据!加载完毕隐藏footerveiw。

代码实现:

在添加headerview后面添加footerview并实例化footerview里面loading标示

footview = LayoutInflater.from(this).inflate(R.layout.lv_footview, mlistView, false);

mLoadMore = (TextView) footview.findViewById(R.id.tv_loadmore);

mlistView.addFooterView(footview);

实现listview的滚动监听事件,并在onscroll()方法中完成异步加载数据的操作

mlistView.setOnScrollListener(new AbsListView.OnScrollListener(){

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

}

@Override

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

//使用isLoading布尔值作为标识符避免每次触底时进行多次加载

if(view.getLastVisiblePosition()==view.getCount()-1&&!isLoading){

mLoadMore.setVisibility(View.VISIBLE);

isLoading=true;

//new 一个一部任务执行异步任务加载操作!

new AsyncTask>() {

@Override

protected List doInBackground(Void... params) {

SystemClock.sleep(1500);

List loadItems=refreshDate("Old");

return loadItems;

}

@Override

protected void onPostExecute(List loadItems) {

isLoading=false;

mLoadMore.setVisibility(View.GONE);

mAdapter.addDate(loadItems,false);

mAdapter.notifyDataSetChanged();

}

}.execute();

}

}

});

最后我们来看一下我们的效果图:

1460000006788259

后记

由于字数的限制,所以整篇不能放在一篇里面!那就先分享前面四个点!第五点就明天继续分享!如果着急的也可先直接去上面的git地址下载源码自己!如果有任何问题,欢迎大家在我的微信公众号【Android程序员日记】里问我!

本篇未完待续,明天继续分享!

喜欢的可以关注我的微信公众号!

1460000006788260

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值