前一段时间做了一个移动办公阅读App,学到了挺多东西,现在把Excel的表格实现跟大家分享一下
首先看看布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MyTable" >
<TextView
android:id="@+id/blank_tv"
android:layout_width="35dp"
android:layout_height="35px"
android:background="@drawable/top02"/>
<com.example.mytable.CustomHScrollView
android:id="@+id/row_scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/white"
android:layout_toRightOf="@id/blank_tv"
android:scrollbars="none"
android:overScrollMode="always">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TableLayout
android:id="@+id/row_head_tab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="*">
</TableLayout>
</LinearLayout>
</com.example.mytable.CustomHScrollView >
<com.example.mytable.CustomScrollView
android:id="@+id/line_scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/blank_tv"
android:background="@color/white"
android:scrollbars="none"
android:overScrollMode="always">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TableLayout
android:id="@+id/line_head_tab"
android:layout_width="35dp"
android:layout_height="match_parent"
android:stretchColumns="*">
</TableLayout>
</LinearLayout>
</com.example.mytable.CustomScrollView>
<com.example.mytable.CustomHScrollView
android:id="@+id/view_h_scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/row_scroll"
android:layout_toRightOf="@id/line_scroll"
android:background="@color/white"
android:scrollbars="none"
android:overScrollMode="always">
<com.example.mytable.CustomScrollView
android:id="@+id/view_v_scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TableLayout
android:id="@+id/tablelayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="*"
android:orientation="vertical">
</TableLayout>
</LinearLayout>
</com.example.mytable.CustomScrollView >
</com.example.mytable.CustomHScrollView>
</RelativeLayout>
可以看到,第一个TextView是一个空白的TextView,它什么都不做,就是表格左上角用来连接行号和列号的而已。
然后,我用了四个滚动视图,一个水平滚动视图用来表示列号,一个垂直滚动视图表示行号,另外一个垂直和水平视图相互嵌套,用来展示Excel的数据,在每个ScrollView里面,我用了TableLayout,它能将以一行一行的形式呈现。此外,我用到了自定义的滚动视图,接下来我们会看到它的作用
我们先看看是怎么往表格中添加数据的
我们调用了四个函数,他们分别往视图里面添加了行号,列号和模拟的Excel数据,并将视图绑定(后面介绍),这里,我只说明addToView()函数,它将Excel的模拟数据添加到了视图当中,添加列号和行号同理,请看
<@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_table);
//初始化视图
addToLineHead(MIN_LINE_NUM);
addToRowHead(MIN_ROW_NUM);
addToView(MIN_ROW_NUM, MIN_LINE_NUM);
//绑定视图,同步
synScrollViews();
}
/**
* @param number 添加的行,列的数量
* 往视图中添加数据
*/
public void addToView(int rowNum, int lineNum)
{
mTable = (TableLayout)findViewById(R.id.tablelayout); //获得视图中的table
mTable.setStretchAllColumns(true);
TableLayout.LayoutParams tableLparams = new TableLayout.LayoutParams(
TableLayout.LayoutParams.WRAP_CONTENT,
TableLayout.LayoutParams.WRAP_CONTENT);
tableLparams.setMargins(0, 0, 0, 0);
mViewEt = new MyTextView(this);
//设置TextView的各个属性
mViewEt.setLayoutParams(new android.widget.TableRow.LayoutParams(DEFAULT_WIDTH,
DEFAULT_HEIGHT));
mViewEt.setBackgroundResource(R.drawable.my_textview);
mViewEt.setGravity(Gravity.CENTER);
mViewEt.setTextSize(TEXT_SIZE); //字体大小
mViewEt.setTextColor(Color.parseColor("#095583")); //文本颜色
//行
for(int i=1; i <= lineNum; ++i)
{
TableRow tablerow = new TableRow(ExcelTable.this);
//列
for(int j=1; j <= rowNum; ++j)
{
MyTextView cloneViewTv = mViewEt.clone(); //关键点
cloneViewTv.setText(String.valueOf(i*j));
tablerow.addView(cloneViewTv); //将这个TextView添加到表格中的行
}
mTable.addView(tablerow, tableLparams);
}
}
这个函数先是获取了在滚动视图中的TableLayout,接着,我们又获得了Table的Row,它代表Table的一行,然后我们就可以将TextView添加到这个Row中了,再把这一行添加到Table里,一行一行的添加,就形成了Excel似的表格,上面,我用了自定义的TextView,它实现了
克隆方法,这是很
关键的一点,因为它大大提高了Excel表格打开的速度,不然假如要生成的Excel单元格(也就是TextView)过多的话,它要花去极大的时间去初始化生成各个TextView,看看MyTextView的代码
public class MyTextView extends TextView implements Cloneable{
public MyTextView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public MyTextView clone()
{
MyTextView editText = null;
try
{
editText = (MyTextView)super.clone();
}
catch (CloneNotSupportedException e)
{
e.printStackTrace();
}
return editText;
}
}
接下来,我们要实现列号的水平ScrollView和显示数据的水平ScrollView同步滚动,垂直的 ScrollView和显示数据的垂直ScrollView同步滚动
/**
* 绑定视图同步显示
*/
private void synScrollViews()
{
mHRowHeadScrollView = (CustomHScrollView)findViewById(R.id.row_scroll);
mHViewScroll = (CustomHScrollView)findViewById(R.id.view_h_scroll);
mLineScrollView = (CustomScrollView)findViewById(R.id.line_scroll);
mViewScroll = (CustomScrollView)findViewById(R.id.view_v_scroll);
//绑定
mHRowHeadScrollView.setScrollView(mHViewScroll);
mHViewScroll.setScrollView(mHRowHeadScrollView);
mLineScrollView.setScrollView(mViewScroll);
mViewScroll.setScrollView(mLineScrollView);
}
/**
* @param view
* 实现同步显示
*/
public void setScrollView(View view)
{
mView = view;
}
很简单,就是在ScrollView里面定义了一个View,然后传递引用,这有什么用呢?当我们滑动ScrollView的时候,ScrollView会自动调用onScrollChanged(int l, int t, int oldl, int oldt)方法,所以,当我们滑动一个ScrollView的时候,只需要在这个函数里面处理绑定的视图的滑动就可以了,请看
protected void onScrollChanged(int l, int t, int oldl, int oldt)
{
super.onScrollChanged(l, t, oldl, oldt);
if(mView!=null)
{
mView.scrollTo(l, t); <span style="white-space:pre"> </span>//滚动到相应的点
}
}
这样,就实现了视图之间的同步滚动了。但是,还有一个问题,两个ScrollView嵌套的时候,用手滑动的时候,这个滑动事件是先给水平的ScrollView呢?还是先给垂直的ScrollView呢?这势必会造成混乱,所以必须要处理一下
public CustomScrollView(Context context) {
super(context);
// TODO Auto-generated constructor stub
mGestureDetector = new GestureDetector(new VScrollDetector());
setFadingEdgeLength(0);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) { //拦截事件
return super.onInterceptTouchEvent(ev) && mGestureDetector.onTouchEvent(ev);
}
// 返回失败如果我们的手势是横向滑动
class VScrollDetector extends SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if(Math.abs(distanceY) > Math.abs(distanceX)) { //如果手势垂直滑动的距离大于水平滑动的距离
return true;
}
return false;
}
}
通过在ScrollView自定义一个手势,拦截事件,并水平和垂直滑动的距离,来得出应该往哪个方向滑动,这样一个Excel的表格就差不多能用了。当然,这个方法还是有很多不足之处,希望大神们指教!
GitHub源码地址:Https://github.com/CatMHW