美高梅平台下载-美高梅娱乐平台登录

热门关键词: 美高梅平台下载,美高梅娱乐平台登录

要实现一个表格很容易,考虑不响应任何事件的

日期:2019-09-30编辑作者:美高梅平台下载

本篇给TableView添加几个事件处理,简单来说分为两种:整行响应事件和单元格响应事件,考虑不响应任何事件的话就是三种,如下:

在Android中,要实现一个表格很容易,直接一个原生控件ListView或者GridView就行了,网上也有很多自定义TableView的思路和成品代码,在这里自己尝试使用ListView实现一个自定义的表格View,里面没有什么高大上的技术,主要是练习一些平时学习积累的小知识点并与大家分享(顺便练习一下Markdown的使用 ^ ^!),所以代码应该是很容易看懂的。

以下内容为原创,转载请注明:

  1. 不响应事件
  2. item响应事件:点击、长按
  3. 单元格响应事件:点击、点击+选中

本篇主要介绍这个TableView的实现原理 (之后会有一些简单的扩展)。

来自天天博客:

其他情况(比如item可以响应事件同时某一列单元格也可以响应事件)有需要的话可以根据本篇的思路自行扩展。

首先从表格整体来看,要求能上下滑动,列数太多的时候能左右滑动,这个使用ListView和横向的HorizontalScrollView就能实现,再考虑表格有一个标题栏,最终就确定了TableView的整体布局如图所示

 

明确需求之后,再理一下整体的实现思路,第1点什么都不用做,第2点很简单,注册ListView的item点击和长按事件即可,第3点也很简单,就是item里面的每个view注册点击事件(都是原生view自带的事件)。

图片 1

本文讲的工具均放在AndroidBucket开源项目中,欢迎大家star/fork,地址:

public static final int MODE_NONE_EVENT = 0; //不处理任何事件public static final int MODE_ITEM_EVENT = 1; //item处理事件public static final int MODE_ALL_UNIT_EVENT = 2; //所有单元格处理事件public static final int MODE_EITHER_UNIT_EVENT = 3; //某列单元格处理事件// 上面的 MODE_ALL_UNIT_EVENT 和 MODE_EITHER_UNIT_EVENT 算一种

private int mEventMode;

// item处理事件if (mEventMode == MODE_ITEM_EVENT) { mContentListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // item点击事件 } }); mContentListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { //item长按事件 return true; } });}//单元格处理事件,在getView里面if (mEventMode == MODE_ALL_UNIT_EVENT || mEventMode == MODE_EITHER_UNIT_EVENT) { Point coordinate = new Point(i, position); //column=x, row=y childView.setTag(coordinate); //记录单元格坐标 childView.setOnTouchListener(touchListener); //这里使用OnTouch实现点击,不用OnClick}

图一 TableView的布局

 

3.1 解释一下上面单元格处理事件的一些东西

使用OnTouch而不使用OnClick是因为方便设置单元格点击时按下状态的颜色变化注册事件是在Adapter的getView方法里面,所以不要使用局部匿名类的方式注册,避免频繁创建对象,上面代码参数touchListener是在getView方法之外定义的成员匿名类,代码如下

private View.OnTouchListener touchListener = new OnTouchListener() { private boolean isContainsUnit = false; @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (mIsUnitSelectable) { Point coordinate =  v.getTag(); //获取单元格坐标 isContainsUnit = mUnitSelectedMap.containsKey(coordinate); int color = isContainsUnit ? mUnitBackColor : mUnitSelectedColor; v.setBackgroundColor; } else { v.setBackgroundColor(mUnitDownColor); } } else if (event.getAction() == MotionEvent.ACTION_UP) { // UP的时候处理点击事件 Point coordinate =  v.getTag(); if (mUnitClickListener != null) { mUnitClickListener.onUnitClick(coordinate.y, coordinate.x, getRowData(coordinate.y)[coordinate.x]); } if (mIsUnitSelectable) { if (isContainsUnit) { mUnitSelectedMap.remove(coordinate); } else { mUnitSelectedMap.put(coordinate, getRowData(coordinate.y)[coordinate.x]); } } else { v.setBackgroundColor(mUnitBackColor); } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { if (mIsUnitSelectable) { int color = isContainsUnit ? mUnitSelectedColor : mUnitBackColor; v.setBackgroundColor; } else { v.setBackgroundColor(mUnitBackColor); } } return true; }};

touchListener里面实现了点击和选中的逻辑。

因为不使用局部匿名类的方式注册,所以touchListener里面不能直接取得单元格view的行列坐标,这里利用了view的Tag实现坐标的记录与获取

上面3注册回调事件之后已经可以响应相应的事件了,但是原生的回调并不能完美满足需求。看图

图片 2注册回调示例

上图说明了为什么要定义一个自己的回调,同时也展示了TableView最终对外提供注册单元格点击事件的方法的使用。

有了图,就可以看图写代码了
(1) 首先定义一个继承自HorizontalScrollView的类,取名TableView
public class TableView extends HorizontalScrollView {}

主要实现聊天功能中的发送不同类型的信息,比如纯文本、图片、语音、图文混排多媒体的数据等(具体效果看微信)。

4.1 如何实现自己的回调(掌握回调的就不用看了,实现上图的效果就行)
// 1.首先定义一个回调接口public interface OnUnitClickListener { void onUnitClick(int row, int column, String unitText);}// 2.然后定义一个接口对象private OnUnitClickListener mUnitClickListener;// 3.在适当的地方调用接口里面的函数,并把相应的参数传进去(适当的地方在 3.1 的代码里)mUnitClickListener.onUnitClick(row, column, unitText);// 4.对外提供一个注册回调的方法public void setOnUnitClickListener(OnUnitClickListener listener) { mUnitClickListener = listener;}// 5.像4的代码截图里面那样使用

在注册回调的时候需要设置相应的事件模式,以下选其一

tv.setEventMode(TableView.MODE_NONE_EVENT);//不处理任何事件tv.setEventMode(TableView.MODE_ITEM_EVENT);//item处理点击和长按事件tv.setEventMode(TableView.MODE_ALL_UNIT_EVENT);//所有单元格处理事件tv.setEventMode(TableView.MODE_EITHER_UNIT_EVENT);//某些列的单元格处理事件tv.setColumnEventIndex;//设置哪些列的单元格处理事件

其它相关

tv.setUnitSelectable;//单元格处理事件的时候是否可以选中tv.setUnitDownColor(R.color.blue_color);//单元格处理事件的时候,按下态的颜色tv.setUnitSelectedColor(R.color.cyan_color);//单元格被选中的颜色Map<Point,String> selectedData = tv.getSelectedUnits();//获取所有选中的单元格数据tv.clearSelectedUnits();//清除所有选中的单元格tv.setUnitSelected;//在单元格可以被选中的时候,通过代码设置第1行第2列的单元格被选中

地址:

图片 3运行效果图

上一篇: Android自定义TableView 扩展 - 样式

(2) 然后新建一个放到 HorizontalScrollView 里面的布局文件 table_view_layout.xml

这里使用AdapterTypeRender在BaseTypeAdapter(这个之后会讲到)中实现。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/table_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >


    <FrameLayout
        android:id="@+id/table_header"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <View
        android:id="@+id/table_header_divider"
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:layout_below="@id/table_header"
        android:background="#2c2c2c" />

    <ListView
        android:id="@+id/table_content_list"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_below="@id/table_header_divider"
        android:divider="#2c2c2c"
        android:dividerHeight="1px"
        android:fadeScrollbars="false"
        android:scrollbars="none" />

</RelativeLayout>

这里主要的实现方式是在ChatAdapter(继承BaseTypeAdapter)中根据每个position的item的type,来使用不同的AdapterTypeRender渲染器进行渲染。渲染的过程当然是在getView方法中进行。

(3)布局文件写好之后添加到TableView里面
View.inflate(mContext, R.layout.table_view_layout, this);
这里注意inflate的第三个参数是this,相当于用table_view_layout创建一个view,然后TableView.add(view)的效果,之后就可以在TableView里面使用 findViewById 方法取得布局里面的view了,如下:

1. AdapterTypeRender

FrameLayout mHeaderLayout = (FrameLayout) findViewById(R.id.table_header);
ListView mContentListView = (ListView) findViewById(R.id.table_content_list);

先来看看AdapterTypeRender这个接口。它有3个方法:getConvertView()、fitEvents()、fitDatas()三个方法。

到这里TableView已经实现了图一上的布局,并且拿到了表头 mHeaderLayout 和 内容列表 mContentListView,接下来只需要往这两个里面添加内容就可以了

package com.wangjie.androidbucket.adapter;

import android.view.View;

/**
 * 用于对不同类型item数据到UI的渲染
 * Author: wangjie
 * Email: tiantian.china.2@gmail.com
 * Date: 9/14/14.
 */
public interface AdapterTypeRender {

    /**
     * 返回一个item的convertView,也就是BaseAdapter中getView方法中返回的convertView
     * @return
     */
    View getConvertView();

    /**
     * 填充item中各个控件的事件,比如按钮点击事件等
     */
    void fitEvents();

    /**
     * 对指定position的item进行数据的适配
     * @param position
     */
    void fitDatas(int position);

}

首先定义两个方法,添加的内容由这两个方法提供,如下代码:

-getconvertView()方法用于返回给BaseTypeAdapter一个convertView,一个AdapterTypeRender实现类对应一个convertView实例,该AdapterTypeRender可以被重用,所以convertView也可以被重用了。

本文由美高梅平台下载发布于美高梅平台下载,转载请注明出处:要实现一个表格很容易,考虑不响应任何事件的

关键词:

View 的测量是在 onMeasure() 方法中进行,继承子V

1一个高度满屏也就是match_parent,宽度自定义的一个VIew, 不是系统组合控件 ,需要全部自己绘制 2 需要向外抛出自定...

详细>>

注解处理器,接下我们将学习使用APT

主目录见:Android高级进阶知识我们在开发的时候为了提高效率往往会选择一个基于注解的框架,但是有时使用反射通...

详细>>

任何一个包含n个节点完全二叉树(满足从根节点开

一直以来,我都很少使用也避免使用到树和图,总觉得它们神秘而又复杂,但是树在一些运算和查找中也不可避免的要...

详细>>

知乎著作权归作者所有,2017 Android暑期实习生面

一个多月没有更新博客了,一直在忙着找工作。现在已经尘埃落定,最终选择了网易。这篇文章主要总结一下自己秋...

详细>>