android怎么在recycleview footview

android怎么在recycleview footview,第1张

如果你对RecyclerView不陌生的话,你一定遇到过这样的情况,我想给RecyclerView加个headerView或者footerView,当你敲出addHeaderView,你会发现并没有添加头部或者底部View的相关API。
那么本文主要的内容很明显了,完成以下工作:
如何为RecyclerView添加HeaderView(支持多个)
如何为RecyclerView添加FooterView(支持多个)
如何让HeaderView或者FooterView适配各种LayoutManager
恩,其实本来我是想偷个懒的,因为Loader写过一篇类似的文章,文章见文末参考链接。但是我发现被别的公众号推送了~~
那我只能考虑自己换种思路来解决这个问题,并且提供尽可能多的功能了~
本文首发于我的公众号,欢迎扫码关注(二维码见左侧栏)。

动态设定section高度的方法
可以试下。
-(CGSize)collectionView:(UICollectionView)collectionView layout:(UICollectionViewLayout)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
if(section == 0)
{
CGSize size = {320, 150};
return size;
}
else
{
CGSize size = {320, 50};
return size;
}
}
在前面我们已经学过,每个collection view都必须有数据源为其提供内容。它的责任是为collection views完成以下的事情:
控制collection view的section数目
每个section中的item的个数
为特定的数据项提供cell view
显然,简单的Recipe app,我们在前面的教程中包含了其中一个部分,在这里我们将继续讲讲collection view并且告诉你如何利用不同的section组织items,你将会学到怎样为collection view添加header视图和footer视图。
如果你没有看过前面的教程,建议你去看一看前面的教程,或者你可以到这里下载here。
Split Recipes into Two Sections in UICollectionView
在这个简单的程序中,RecipeCollectionViewController是集合视图的数据源对象,为了把视图分成两个部分,我们需要有一些变化,接下来我们完成:
起先,recipeImages数组是存储所有recipes的名称,因为我们想把recipes分成两组,我们要修改我们的代码,并使用签到数组来存储不同的recipe,也许你还不明白啥是嵌入的数组,下面的会让你明白的。第一组包含主要的图像,而另一个为drink和dessert。顶级数组(即recipeImages)包含两个数组,每个数组部分的特定区域包含特定的data items。
Nested Array Explained
让我们开始编写代码,在RecipeCollectionViewControllerm中初始化"recipeImages"数组,并在viewDidload方法中写下面的方法:
- (void)viewDidLoad
{
[super viewDidLoad];
//Initialize recipe image array
NSArray mainDishImages = [NSArray arrryWithObjects:@"egg_benedictjpg", @"full_breakfastjpg", @"ham_and_cheese_paninijpg", @"ham_and_egg_sandwichjpg", @"hamburgerjpg", @"instant_noodle_with_eggjpg", @"japanese_noodle_with_porkjpg", @"mushroom_risottojpg", @"noodle_with_bbq_porkjpg", @"thai_shrimp_cakejpg", @"vegetable_curryjpg", nil];
NSArray drinkDessertImages = [NSArray arrayWithObjects:@"angry_birds_cakejpg", @"creme_breleejpg", @"green_teajpg", @"starbucks_coffeejpg", @"white_chocolate_donutjpg", nil];
recipeImages = [NSArray arrayWithObjects:mainDishImages,drinkDesserImages,nil];
}
上面的代码将recipes images分成两组。接下来,修改"numberOfIntemsInSecion:"方法来返回,每个secions中的items数目:
- (NSInteger)collectionView:(UICollectionView)collectionView numberOfItemsInSecion:(NSInteger)section
{
return [[recipeImages objectAtIndex:sectin]count];
}
接下来我们按照下面的方法修改"cellForItemAtIndexPath:"方法
- (UICollectionVIewCell )collectionView:(UICollectionView)collectionView cellForItemAtIndexPath:(NSIndexPath )indexPath
{
static NSString identifier = @"Cell";
RecipeViewCell cell = (RecipeViewCell )[collectionView dequeueReuseIdentifier:identifier forIndexPath:indexPath];
UIImageView recipeImageView = (UIImageView )[cell viewWithTag:100];
recipeImageViewimage = [UIImage imagedNamed:[recipeImages[indexPathsection] objectAtIndex:indexPathrow]];
cellbackgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"photo-frame-2png"]];
return cell;
}
你可以和以前的代码比较以下,你就会知道只有一样是唯一的变化。我们首先检索该数组的section number然后从section中获取具体的items。
最后,怎样给collection view实现两个section,这个可以通过方法调用下面的方法来完成即:在RecipeCollectionViewControllerm中的numberOfSectionsInCollectionView方法,在collectin View中返回section中的数量。
- (NSInteger)numberOfSectionsInCollectionVIew:(UICollectionView )collectionView
{
return [recipeImages count];
}
现在运行你的app,你会在屏幕上看到下面的显示
Recipe App with Two Sections
Tweak the Margin of Your Content using Section Insets
(利用Section Insets)
程序是完成了,但是你是否觉得看起来并不怎么顺眼呢?图像的第一部分的最后一行和第二部分的第一样靠的太近。我们可以使用插入图到内容周围的空间中来改变一些格局,通过下图你可以比较直观 的看到影响:
Add margin using section insets
你可以利用UIEdgeInsetsMake来完成插入:
insert = UIEdgeInsetsMake(top,left,botton,right);
在我们的Recipe app中我们只能在两个section之间添加空间。在RecipeCollectionViewControllerm文件中的ViewDidLoad方法中,添加下面的方法:
UICollectionViewFlowLayout collectionViewLayout = (UICollectionViewFlowLayout )selfcollectionViewFlowLayout;
collectionViewLayoutsectionInset = UIEdegeInsetsMake(20,0,0,0);
上面的代码实现了在collection view中创建和添加插入。现在我们运行程序,你将会看到下面的 图像显示,我们在两个section之间增加了一些空间。
Recipe Collection View with Insets
添加头部和底部视图
现在我们进一步调整应用程序,让其更酷。让我们来给应用程序添加头部和底部视图,我们利用UICollectionViewFlowLayout来实现这一点。这里的header和footer视图可以被称为流布局的补充。在默认情况下,这些视图是在流布局中禁用的。但可以通过下面几件事情来配置header和footer视图:
为了尽量保持简单,所以我们可以选择storyboard来实现(当然这不是必须的,你同样可以使用代码来实现这一点)
实现 UICollectionViewDataSource协议的 collectionView:viewForSupplementaryElementOfKind 方法,并通过这个方法来实现补充试图在collection view中显示。
在Storyboard中设计Header和Footer
首先download the header/footer background images并且添加到Xcode工程中。
到Storyboard中,选择collection view controller中的"Collection View"。在Attributes inspector中,选择"Section Header"和"Section Footer",一旦选中你就会在屏幕中看到下面的的显示:
Storyboard Enables Section Header and Footer
在header和footer之间默认为空,我们会用storyboard来设计视图。header view是专门用来显示一个部分的标题,而底部视图只显示静态横幅。利用storyboard,从对象库中拖出image view并在其上面添加一个标签。设置字体颜色为白色,底部视图只需添加一个image view。如图:
Design header and footer views
选中footer view中的image view,在Attributes inspector中命名背景为"footer_bannerpng"
Add Footer View Background
最重要的是,我们必须为header和footer view指定一个标识符。这个标示符将会被用于代码识别名称。在Atteributes inspector中设置header view的identifier为“HeaderView”,同样的把footer view的identifier设置为“FooterView”。
Collection Reusable View Header Identifier
为Header View添加新类
在默认情况下,header和footer view和UICollectionResuable类相关联。为了在header view中显示我们需要的背景和标题,我们必须创建一个新的继承自UICollectionResuableView的类,我们可以命名为RecipeCollectionHeaderView。
Add Collection Header View Class
在storyboard的Identifier inspector中的sustom class设置为“RecipeCollectionHeaderView”。按住Ctrl键,单机header中的image view,并拖向RecipeCollectionHeaderViewh中插入一个Outlet 变量。命名变量为"backgroundImage"。重复同样的步骤对UILabel实现,然后命名为"title"。
Establish connection with RecipeCollectionHeaderVeiw
实现viewForSupplementaryElementOfKind方法
如果你尝试运行应用程序,你可能不会看到header和footer,这是因为我们还没有实现"viewFOrSupplementaryElementOfKind:"方法。选择“RecipeCollectionViewController”,并添加import语句。
#import "RecipeCollectionHeaderViewh"
下面就是实现viewforSupplementaryElementOfKind方法的代码:
- (UICollectionReusableView )collectionView:(UICollectionView )collectionView viewForSupplementaryElementOfKind:(NSString )kind atIndexPath:(NSIndexPath )indexPath
{
UICollectionReusableView reusableview = nil;
if (kind == UICollectionElementKindSectionHeader){
RecipeCollectionHeaderView headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath];
NSString title = [[NSString alloc] initWithFormat:@"Recipe Group #%i",indexPathsection +1];
headerViewtitletext = title;
UIImage headerImage = [UIImage imageNamed:@"header_bannerpng"];
headerViewbackgroundImageimage = headerImage;
reusableView = headerView;
}
if (kind == UICollectionElementKindSectionFooter){
UICollectionReusableView footerview = [collectionView dequeueResuableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"FooterView" forIndexPath:indexPath];
reusableview = footerview;
}
return reusableview;
}
上面的代码告诉它页眉/页脚视图应该在每个部分中使用collect view。我们首先确定该集合视图要求header或footer view。这可以通过使用一种变量来完成。对于头来看,我们出列header view(使用dequeueReusableSupplementaryViewOfKind :方法),并设置适当的标题和图像。正如你可以从两个if之间的代码,我们使用我们之前分配给获得header/footer view标识符。
现在运行代码,我们可以看到运行的结果:
Recipe App with Header and Footer

handler其实就是消息处理机制。首先在主线程也就是UI创建一个Handler对象,复写其中的handMessage( Message msg)方法。该方法里的msg就是子线程发来的消息,表示子线程处理完了,以这个msg来通知主线程。让主线程来作UI的绘制工作。
那么子线程工作完了就要发消息了,比如:
run(){
data = getDataFromInternet();//耗时工作
Message msg = handlerobtainMessage(0, data);//通过handler得到消息,该消息的标识为0,消息内容是data
handlersendMessage(msg);//发送
}
然后handler在主线程就负责接收:
public Handler handler = new Handler(){//处理UI绘制
@SuppressWarnings("unchecked")
@Override
public void handleMessage(Message msg) {
switch (msgwhat) {
case 0:
data = (List<Map<String, Object>>) msgobj;
if(data == null){
ToastmakeText(AllMovieActivitythis, "网络连接失败,获取不到影片信息", 1)show();
}else {

adapter = new HotMoviedapter(AllMovieActivitythis, data, Rlayoutallmovielist_item,
new String[] { "picurl", "chname", "director", "leadrole",
"fshowtime", "country" }, new int[] { Ridpicurl,
Ridchname, Riddirector, Ridleadrole,
Ridfshowtime, Ridcountry },mListView);
TextView v = new TextView(AllMovieActivitythis);
vsetHeight(80);
vsetSelectAllOnFocus(false);
mListViewaddFooterView(v);
mListViewsetAdapter(adapter);
}
break;
default:
break;
}
}
};

首先我说明一下这篇文章实现的效果是怎样的。
我这里写上中下三个layout来写。

所有的前提都是先建一个项目,建项目不会的请看我的另一个笔记>listView完整分页代码,请参考:
package comnoticemoredate;
import javautilArrayList;
import javautilHashMap;
import androidappActivity;
import androidosBundle;
import androidosHandler;
import androidviewView;
import androidviewViewOnClickListener;
import androidwidgetAbsListView;
import androidwidgetAbsListViewOnScrollListener;
import androidwidgetButton;
import androidwidgetListView;
import androidwidgetProgressBar;
import androidwidgetSimpleAdapter;
import androidwidgetToast;
public class MoreDateListActivity extends Activity implements OnScrollListener {

// ListView的Adapter
private SimpleAdapter mSimpleAdapter;
private ListView lv;
private Button bt;
private ProgressBar pg;
private ArrayList<HashMap<String,String>> list;
// ListView底部View
private View moreView;
private Handler handler;
// 设置一个最大的数据条数,超过即不再加载
private int MaxDateNum;
// 最后可见条目的索引
private int lastVisibleIndex;

/ Called when the activity is first created /
@Override
public void onCreate(Bundle savedInstanceState) {
superonCreate(savedInstanceState);
setContentView(Rlayoutmain);
MaxDateNum = 22; // 设置最大数据条数
lv = (ListView) findViewById(Ridlv);
// 实例化底部布局
moreView = getLayoutInflater()inflate(Rlayoutmoredate, null);
bt = (Button) moreViewfindViewById(Ridbt_load);
pg = (ProgressBar) moreViewfindViewById(Ridpg);
handler = new Handler();
// 用map来装载数据,初始化10条数据
list = new ArrayList<HashMap<String,String>>();
for (int i = 0; i < 10; i++) {
HashMap<String, String> map = new HashMap<String, String>();
mapput("ItemTitle", "第" + i + "行标题");
mapput("ItemText", "第" + i + "行内容");
listadd(map);
}
// 实例化SimpleAdapter
mSimpleAdapter = new SimpleAdapter(this, list, Rlayoutitem,
new String[] { "ItemTitle", "ItemText" },
new int[] { Ridtv_title, Ridtv_content });
// 加上底部View,注意要放在setAdapter方法前
lvaddFooterView(moreView);
lvsetAdapter(mSimpleAdapter);
// 绑定监听器
lvsetOnScrollListener(this);
btsetOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
pgsetVisibility(ViewVISIBLE);// 将进度条可见
btsetVisibility(ViewGONE);// 按钮不可见
handlerpostDelayed(new Runnable() {
@Override
public void run() {
loadMoreDate();// 加载更多数据
btsetVisibility(ViewVISIBLE);
pgsetVisibility(ViewGONE);
mSimpleAdapternotifyDataSetChanged();// 通知listView刷新数据
}
}, 2000);
}
});
}
private void loadMoreDate() {
int count = mSimpleAdaptergetCount();
if (count + 5 < MaxDateNum) {
// 每次加载5条
for (int i = count; i < count + 5; i++) {
HashMap<String, String> map = new HashMap<String, String>();
mapput("ItemTitle", "新增第" + i + "行标题");
mapput("ItemText", "新增第" + i + "行内容");
listadd(map);
}
} else {
// 数据已经不足5条
for (int i = count; i < MaxDateNum; i++) {
HashMap<String, String> map = new HashMap<String, String>();
mapput("ItemTitle", "新增第" + i + "行标题");
mapput("ItemText", "新增第" + i + "行内容");
listadd(map);
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// 计算最后可见条目的索引
lastVisibleIndex = firstVisibleItem + visibleItemCount - 1;
// 所有的条目已经和最大条数相等,则移除底部的View
if (totalItemCount == MaxDateNum + 1) {
lvremoveFooterView(moreView);
ToastmakeText(this, "数据全部加载完成,没有更多数据!", ToastLENGTH_LONG)show();
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// 滑到底部后自动加载,判断listview已经停止滚动并且最后可视的条目等于adapter的条目
if (scrollState == OnScrollListenerSCROLL_STATE_IDLE
&& lastVisibleIndex == mSimpleAdaptergetCount()) {
// 当滑到底部时自动加载
// pgsetVisibility(ViewVISIBLE);
// btsetVisibility(ViewGONE);
// handlerpostDelayed(new Runnable() {
//
// @Override
// public void run() {
// loadMoreDate();
// btsetVisibility(ViewVISIBLE);
// pgsetVisibility(ViewGONE);
// mSimpleAdapternotifyDataSetChanged();
// }
//
// }, 2000);
}
}

}

collectionView和table基本用法一样但是header和footer,就找不到方法了
自己找了好久网上也没个人写的就一个写的是用storyBoard写的 对于纯代码的可能不怎么太理解。
自己摸索的做出来了。下面纯代码的步骤:<语文水平渣 没什么文采,但是技术点肯定会说明白的>
如果要给你的collectionView添加header和footer,他的数据源和代理是没有直接提供创建方法的,但是提供了一个两用的方法
[objc] view plain copy
<span style="font-size:14px;">- (UICollectionReusableView )collectionView:(UICollectionView )collectionView viewForSupplementaryElementOfKind:(NSString )kind atIndexPath:(NSIndexPath )indexPath
</span>
如果要给你的collectionView添加header和footer步骤<本文只以header为例>
1设置流水布局 ,需要在流水布局里设置header和footer的size
[objc] view plain copy
- (id)init
{
// UICollectionViewLayout;
UICollectionViewFlowLayout flow = [[UICollectionViewFlowLayout alloc] init]; // 流水布局
[objc] view plain copy
[objc] view plain copy
<span style="white-space:pre"> </span>// 设置header的Size
<span style="color:#ff6666;"> flowheaderReferenceSize = CGSizeMake(320, 44);</span>
[objc] view plain copy
// 设置格子的宽高
flowitemSize = CGSizeMake(75, 61);
// 设置列距
flowminimumInteritemSpacing = 5;
// 设置行距离
// flowminimumLineSpacing = 0;
// 设置整体内容和四周的边距
// top left bottom right
flowsectionInset = UIEdgeInsetsMake(20, 2, 0, 2);
return [super initWithCollectionViewLayout:flow];
}
2 创建UICollectionReusableView的子类UICollectionHeaderView,并创建其xib 设置xib的identifier为header
[objc] view plain copy
<span style="font-size:14px;">#import <UIKit/UIKith>
@interface UICollectionHeaderView : UICollectionReusableView
@end
</span>
3在xib中添加你需要显示的控件,不要忘了class继承UICollectionHeaderView。
4在collectionViewController 的viewDidLoad注册xib,方法和注册cell差不多 只不过方法名不一样
[objc] view plain copy
<span style="font-size:14px;">UINib nib = [UINib nibWithNibName:@"WdViewCell" bundle:nil] ;
[selfcollectionView registerNib:nib forCellWithReuseIdentifier:@"cell"];
[selfcollectionView setBackgroundColor:[UIColor colorWithRed:240 green:240 blue:240 alpha:08]];
</span>
[objc] view plain copy
<span style="font-size:14px;">// 注册header的
UINib header = [UINib nibWithNibName:@"UICollectionHeaderView" bundle:nil];
[selfcollectionView registerNib:header forSupplementaryViewOfKind:<span style="color:#ff6666;">UICollectionElementKindSectionHeader</span> withReuseIdentifier:@"header"];</span>
5显示header
这个方法:kind标识你是header还是footer<可能还有其他的>header:UICollectionElementKindSectionHeader,用个判断或者switch就可以选择你要显示什么类容了,创建header view的方法
[objc] view plain copy
<span style="font-size:14px;">// 设置每组的标题
- (UICollectionReusableView )collectionView:(UICollectionView )collectionView viewForSupplementaryElementOfKind:(NSString )kind atIndexPath:(NSIndexPath )indexPath
{
if (kind == UICollectionElementKindSectionHeader) {
UICollectionHeaderView headerView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"header" forIndexPath:indexPath];
</span>
[objc] view plain copy
<span style="font-size:14px;">// 在这就可以设置header中子控件的数据了</span>
[objc] view plain copy
<span style="font-size:14px;"> return headerView;
}
else
{
return nil;
}
}</span>
这样就可以显示你的header了


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/13077821.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-30
下一篇 2023-05-30

发表评论

登录后才能评论

评论列表(0条)

保存