- UITableView是iOS中使用很广泛的一种列表控件,类似Android中的RecyclerView(ListView暂不考虑了),继承自UIScrollView,利用复用机制,实现高性能的滑动
1. 最基本的使用
eg:数据源是一个数组,内容如下:
String[] data = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21"};
显示一个简单的列表
-
Android实现
首先添加依赖:
implementation 'androidx.recyclerview:recyclerview:1.1.0'
添加Activity主布局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" />
添加item_view
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/tv_item"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center_vertical"
android:orientation="vertical"
android:padding="10dp"
android:textColor="@android:color/black"
android:textSize="16sp"
tools:text="123" />
在MainActivity中处理代码(Adapter就不分开写了)
package com.dxl.recyclerviewdemo;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.Arrays;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
String[] data = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21"};
private MyAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.recycler_view);
mAdapter = new MyAdapter(this, Arrays.asList(data));
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
}
class MyAdapter extends RecyclerView.Adapter<MyViewHolder>{
private List<String> dataList;
private Context mContext;
public MyAdapter(Context context, List<String> list) {
this.dataList = list;
this.mContext = context;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.view_item, parent, false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
holder.mTextView.setText(dataList.get(position));
}
@Override
public int getItemCount() {
return dataList.size();
}
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView mTextView;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
mTextView = itemView.findViewById(R.id.tv_item);
}
}
}
实现效果:

-
iOS实现
iOS实现起来简单一些,需要的代码量比较小。
创建一个SingleViewApp
打开Main.storyboard,拖拽一个TableView到主界面,调整大小
属性面板里调整Prototype Cells为1,这时左侧布局中会出现一个cell。
点击cell,调整cell属性,Style设置为Basic,添加一个Identifier

拖动tableView到viewController实现数据源和代理
//
// ViewController.m
// testTableView
//
// Created by dxl on 2020/2/9.
// Copyright © 2020 dxl. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()<UITableViewDelegate, UITableViewDataSource>
@property(strong, nonatomic)NSArray *dataArray;
@end
@implementation ViewController
- (NSArray *)dataArray {
if (!_dataArray) {
_dataArray = [NSArray arrayWithObjects:@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"11", @"12", @"13", @"14", @"15", @"16", @"17", @"18", @"19", @"20", @"21", nil];
}
return _dataArray;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"item_cell"];
cell.textLabel.text = self.dataArray[indexPath.row];
return cell;
}
- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataArray.count;
}
@end
运行效果:

2. 分割线
Android RecyclerView默认不带分割线属性,需要自己定义。
1)可以使用默认的分割线
//添加自带默认分割线
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
如果自带的分割线不能满足条件,可以在上述基础上添加一个drawable。
比如定义一个drawable,divider_shape.xml,定义分割线大小为1px,颜色为灰色
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="1px"
android:height="1px" />
<solid android:color="@android:color/darker_gray"/>
</shape>
添加分割线的代码修改以下:
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
dividerItemDecoration.setDrawable(ContextCompat.getDrawable(this, R.drawable.shape_divider));
mRecyclerView.addItemDecoration(dividerItemDecoration);
看一下效果:

如果分割线比较复杂,上面的shape不能满足要求,就需要自定义,我们还是可以自己去添加分割线,RecyclerView提供了一个抽象类ItemDecoration,它是item的装饰类。
iOS UITableView添加分割线
打开storyboard,调整tableview属性,

,设置分割线样式和颜色

iOS UITableView cell 四种样式:
UITableViewCellStyleDefault, // Simple cell with text label and optional image view
UITableViewCellStyleValue1, // Left aligned label on left and right aligned label on right with blue text (Used in Settings)
UITableViewCellStyleValue2, // Right aligned label on left with blue text and left aligned label on right (Used in Phone/Contacts)
UITableViewCellStyleSubtitle // Left aligned label on top and left aligned label on bottom with gray text (Used in iPod)
分别对应storyboard中的四种属性:
Basic,LeftDetail,RightDetail,Subtitle
3. header和footer
iOS中UITableView有两种方式设置header,一种是纯文本,一种是自定义view。
- 纯文本:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
return @"header";
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 50.0f;
}
运行如下:

如果header不是纯文本,或者自带样式不能满足,可以重写下列方法自定义header显示的view
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 100.0f;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
UIView *headerView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, screenWidth, 100)];
headerView.backgroundColor = [UIColor greenColor];
UILabel *label = [[UILabel alloc]initWithFrame:headerView.frame];
label.text = @"自定义视图header";
label.textAlignment = NSTextAlignmentCenter;
[headerView addSubview:label];
return headerView;
}
运行效果如下:

.
注意自定义view 的高度受viewForHeaderInSection的约束,如果不重写viewForHeaderInSection的话,系统会有一个默认高度,但不是自定义view 的高度。
footer同理。
Android RecyclerView
遗憾的是,RecyclerView原生没有提供headerView和footerView等相关的方法,处理的方法只能是把headerView和footerView作为一种viewType在adapter中进行处理。
还是以刚才iOS达到的效果为例:
修改adapter
import android.content.Context;
import android.graphics.Color;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private List<String> dataList;
private Context mContext;
public static final int TYPE_HEADER = 0;
public static final int TYPE_DEFAULT = 1;
@Retention(RetentionPolicy.SOURCE)
@IntDef({TYPE_HEADER, TYPE_DEFAULT})
public @interface ItemType {
}
public MyAdapter(Context context, List<String> list) {
this.dataList = new ArrayList<>(list);
this.dataList.add(0, "");
this.mContext = context;
}
@Override
public @ItemType
int getItemViewType(int position) {
return position == 0 ? TYPE_HEADER : TYPE_DEFAULT;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, @ItemType int viewType) {
View view;
if (viewType == TYPE_HEADER) {
view = new TextView(mContext);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 100);
((TextView) view).setText("自定义header");
((TextView) view).setTextColor(Color.BLACK);
view.setLayoutParams(layoutParams);
view.setBackgroundColor(Color.GREEN);
((TextView) view).setGravity(Gravity.CENTER);
} else {
view = LayoutInflater.from(mContext).inflate(R.layout.view_item, parent, false);
}
return new MyViewHolder(view, viewType);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
int viewType = getItemViewType(position);
if (viewType == TYPE_DEFAULT) {
holder.mTextView.setText(dataList.get(position));
}
}
@Override
public int getItemCount() {
return dataList.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView mTextView;
public MyViewHolder(@NonNull View itemView, @ItemType int itemType) {
super(itemView);
mTextView = itemView.findViewById(R.id.tv_item);
}
}
}
运行查看效果:

4. 点击事件:
UITableView点击事件处理比较简单:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"当前点击的内容是%@", self.dataArray[indexPath.row]);
}
安卓就麻烦些了,因为RecyclerView原生没有提供item点击事件:
修改adapter:
package com.dxl.recyclerviewdemo;
import android.content.Context;
import android.graphics.Color;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private List<String> dataList;
private Context mContext;
private ListenerWithPosition.OnItemPositionClickListener mListener;
public void setListener(ListenerWithPosition.OnItemPositionClickListener listener) {
mListener = listener;
}
public static final int TYPE_HEADER = 0;
public static final int TYPE_DEFAULT = 1;
@Retention(RetentionPolicy.SOURCE)
@IntDef({TYPE_HEADER, TYPE_DEFAULT})
public @interface ItemType {
}
public MyAdapter(Context context, List<String> list) {
this.dataList = new ArrayList<>(list);
this.dataList.add(0, "");
this.mContext = context;
}
@Override
public @ItemType
int getItemViewType(int position) {
return position == 0 ? TYPE_HEADER : TYPE_DEFAULT;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, @ItemType int viewType) {
View view;
if (viewType == TYPE_HEADER) {
view = new TextView(mContext);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 100);
((TextView) view).setText("自定义header");
((TextView) view).setTextColor(Color.BLACK);
view.setLayoutParams(layoutParams);
view.setBackgroundColor(Color.GREEN);
((TextView) view).setGravity(Gravity.CENTER);
} else {
view = LayoutInflater.from(mContext).inflate(R.layout.view_item, parent, false);
}
return new MyViewHolder(view, viewType);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
if (mListener != null) {
holder.itemView.setOnClickListener(new ListenerWithPosition(mListener, position));
}
int viewType = getItemViewType(position);
if (viewType == TYPE_DEFAULT) {
holder.mTextView.setText(dataList.get(position));
}
}
@Override
public int getItemCount() {
return dataList.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView mTextView;
public MyViewHolder(@NonNull View itemView, @ItemType int itemType) {
super(itemView);
mTextView = itemView.findViewById(R.id.tv_item);
}
}
public static class ListenerWithPosition implements View.OnClickListener {
private OnItemPositionClickListener mClickListener;
private int mPosition;
public ListenerWithPosition(OnItemPositionClickListener clickListener, int position) {
mClickListener = clickListener;
mPosition = position;
}
interface OnItemPositionClickListener {
void onClick(View v, int position);
}
@Override
public void onClick(View v) {
if (mClickListener != null) {
mClickListener.onClick(v, mPosition);
}
}
}
}
在MAinActivity中设置点击事件:
mAdapter.setListener(new MyAdapter.ListenerWithPosition.OnItemPositionClickListener() {
@Override
public void onClick(View v, int position) {
Toast.makeText(MainActivity.this, data[position - 1], Toast.LENGTH_LONG).show();
}
});
网友评论