证券炒股软件经常会遇到有很多Tab要显示,使得控件的上下/垂直滚动联动经常要使用到,比如撤单,查询等业务都要用到这个控件,今天刚好项目没那么紧,就把这个控件的实现总结一下。
先看看我们实现后的效果
分析:这里我们用一个水平滑动控件HorizontalScrollView和一个ListView组合实现水平滑动和垂直滑动
一、自定义一个LinearLayout的视图容器控件,截取掉子控件的触摸监听事件,阻止 拦截 ontouch事件传递给其子控件
步骤:新建一个ObserverHScrollViewIntercept类继承LinearLayout重写onInterceptTouchEvent方法,把触摸事件消费掉,不要往子类继续传递。
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;
/**
*一个视图容器控件
* 阻止 拦截 ontouch事件传递给其子控件
* Created by willkong on 2016/11/15.
*/
public class ObserverHScrollViewIntercept extends LinearLayout{
public ObserverHScrollViewIntercept(Context context) {
this(context,null);
}
public ObserverHScrollViewIntercept(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public ObserverHScrollViewIntercept(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
}
二、新建一个ObserverHScrollView类继承HorizontalScrollView
这里主要的技术是写了一个监听观察者,ScrollViewObserver。先给控件添加滑动变化的监听,只要用户一滑动,就通知观察者。
先在该类中写一个观察者类ScrollViewObserver。这个类的主要作用是把监听到的滑动变化回调给调用者,所以,我们要先写一个滑动变化监听回调接口OnScrollChangedListener
/*
* 当发生了滚动事件时,调用这个接口,根据坐标滑动到对应的位置
*/
public static interface OnScrollChangedListener {
public void onScrollChanged(int l, int t, int oldl, int oldt);
}
在观察者类中定义一个list,把监听到的每一次的滚动事件保存起来。并且写两个添加监听和移除监听的方法,还有一个回调接口方法,把监听到的发生滚动事件回调给调用者。
/*
* 观察者
*/
public static class ScrollViewObserver {
List<OnScrollChangedListener> mList;
public ScrollViewObserver() {
super();
mList = new ArrayList<OnScrollChangedListener>();
}
public void AddOnScrollChangedListener(OnScrollChangedListener listener) {
mList.add(listener);
}
public void RemoveOnScrollChangedListener(
OnScrollChangedListener listener) {
mList.remove(listener);
}
public void NotifyOnScrollChanged(int l, int t, int oldl, int oldt) {
if (mList == null || mList.size() == 0) {
return;
}
for (int i = 0; i < mList.size(); i++) {
if (mList.get(i) != null) {
mList.get(i).onScrollChanged(l, t, oldl, oldt);
}
}
}
}
整个类代码:
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;
import java.util.ArrayList;
import java.util.List;
/**
* 自定义的 滚动控件
* 重载了 onScrollChanged(滚动条变化),监听每次的变化通知给 观察(此变化的)观察者
* 可使用 AddOnScrollChangedListener 来订阅本控件的 滚动条变化
* Created by willkong on 2016/11/15.
*/
public class ObserverHScrollView extends HorizontalScrollView{
//新建一个监听者,接口回调使用
ScrollViewObserver mScrollViewObserver = new ScrollViewObserver();
public ObserverHScrollView(Context context) {
this(context,null);
}
public ObserverHScrollView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public ObserverHScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(ev);
}
/**
* 监听控件的滑动变化
* @param l
* @param t
* @param oldl
* @param oldt
*/
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
/*
* 当滚动条移动后,引发 滚动事件。通知给观察者,观察者会传达给其他的。
*/
if (mScrollViewObserver != null /*&& (l != oldl || t != oldt)*/) {
mScrollViewObserver.NotifyOnScrollChanged(l, t, oldl, oldt);
}
super.onScrollChanged(l, t, oldl, oldt);
}
/*
* 订阅 本控件 的 滚动条变化事件
* */
public void AddOnScrollChangedListener(OnScrollChangedListener listener) {
mScrollViewObserver.AddOnScrollChangedListener(listener);
}
/*
* 取消 订阅 本控件 的 滚动条变化事件
* */
public void RemoveOnScrollChangedListener(OnScrollChangedListener listener) {
mScrollViewObserver.RemoveOnScrollChangedListener(listener);
}
/**
* 观察者
*/
public static class ScrollViewObserver{
List<OnScrollChangedListener> mList;
public ScrollViewObserver(){
super();
mList = new ArrayList<OnScrollChangedListener>();
}
/**
* 订阅 本控件 的 滚动条变化事件
* @param listener
*/
public void AddOnScrollChangedListener(OnScrollChangedListener listener) {
mList.add(listener);
}
/**
* 取消 订阅 本控件 的 滚动条变化事件
* @param listener
*/
public void RemoveOnScrollChangedListener(
OnScrollChangedListener listener) {
mList.remove(listener);
}
public void NotifyOnScrollChanged(int l, int t, int oldl, int oldt) {
if (mList == null || mList.size() == 0) {
return;
}
for (int i = 0; i < mList.size(); i++) {
if (mList.get(i) != null) {
mList.get(i).onScrollChanged(l, t, oldl, oldt);
}
}
}
}
/*
* 当发生了滚动事件时,调用这个接口
*/
public static interface OnScrollChangedListener {
public void onScrollChanged(int l, int t, int oldl, int oldt);
}
}
到这里控件就已经编写完毕了,下面我们来讲,怎么使用这个控件。
三、新建一个类HVScorllListviewActivity
首先新建一个头部标题ativity_hvscorll_listview_item的布局文件
<?xml version="1.0" encoding="utf-8"?>
<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="wrap_content"
android:background="@drawable/demo_list_selector"
android:descendantFocusability="blocksDescendants"
android:orientation="horizontal"
android:paddingBottom="10dp"
android:paddingTop="10dp"
tools:context="com.hvscorlllistviewdemo.HVScorllListviewActivity">
<TextView
android:id="@+id/textView1"
android:layout_width="@dimen/bond_table_header_width"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:gravity="center"
android:text="@string/bound_search_result_head_zqmc"
android:textColor="@color/black"
android:textSize="@dimen/bond_table_header_text" />
<com.hvscorlllistviewdemo.ObserverHScrollViewIntercept
android:id="@+id/scroollContainter"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/textView1"
android:focusable="false">
<com.hvscorlllistviewdemo.ObserverHScrollView
android:id="@+id/horizontalScrollView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/textView2"
android:layout_width="@dimen/bond_table_header_width"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/bound_search_result_head_zqjc"
android:textColor="@color/black"
android:textSize="@dimen/bond_table_header_text" />
<TextView
android:id="@+id/textView3"
android:layout_width="@dimen/bond_table_header_width"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/bound_search_result_head_zqdm"
android:textColor="@color/black"
android:textSize="@dimen/bond_table_header_text" />
<TextView
android:id="@+id/textView4"
android:layout_width="@dimen/bond_table_header_width"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/bound_search_result_head_fxjc"
android:textColor="@color/black"
android:textSize="@dimen/bond_table_header_text" />
<TextView
android:id="@+id/textView5"
android:layout_width="@dimen/bond_table_header_width"
android:layout_height="wrap_content"
android:gravity=&