Android 自定义横向滚动条。当你的横向字段或者表格很多时候,显示不下内容,可以使用很想滚动条进行滚动。竖向方面我添加了listview进行添加数据。两者滚动互不干扰。横向滚动条的可以自定义不同的字段的,进行加载就行了。接下来看看效果图,再看代码。
一、效果图
二、自定义MyHScrollView继承HorizontalScrollView
package com.org.scrollview;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;
/*
* 自定义的 滚动控件
* 重载了 onScrollChanged(滚动条变化),监听每次的变化通知给 观察(此变化的)观察者
* 可使用 AddOnScrollChangedListener 来订阅本控件的 滚动条变化
* */
public class MyHScrollView extends HorizontalScrollView {
ScrollViewObserver mScrollViewObserver = new ScrollViewObserver();
public MyHScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public MyHScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public MyHScrollView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
Log.i("pdwy","MyHScrollView onTouchEvent");
return super.onTouchEvent(ev);
}
@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 interface OnScrollChangedListener {
public void onScrollChanged(int l, int t, int oldl, int oldt);
}
/*
* 观察者
*/
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);
}
}
}
}
}
三、InterceptScrollContainer这个类把表头的滚动下发到每一个listview的item中。
package com.org.scrollview;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;
/*
*
* 一个视图容器控件
* 阻止 拦截 ontouch事件传递给其子控件
* */
public class InterceptScrollContainer extends LinearLayout {
public InterceptScrollContainer(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public InterceptScrollContainer(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
//
// @Override
// public boolean dispatchTouchEvent(MotionEvent ev) {
// // TODO Auto-generated method stub
// //return super.dispatchTouchEvent(ev);
// Log.i("pdwy","ScrollContainer dispatchTouchEvent");
// return true;
// }
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
//return super.onInterceptTouchEvent(ev);
Log.i("pdwy","ScrollContainer onInterceptTouchEvent");
return true;
//return super.onInterceptTouchEvent(ev);
}
// @Override
// public boolean onTouchEvent(MotionEvent event) {
// // TODO Auto-generated method stub
// Log.i("pdwy","ScrollContainer onTouchEvent");
// return true;
// }
}
三、自定义统一管理类CustomListScrollManageActivity
package com.org.horizontalscrollview;
import java.util.ArrayList;
import java.util.LinkedList;
import com.org.scrollview.MyHScrollView;
import com.org.scrollview.MyHScrollView.OnScrollChangedListener;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Toast;
public abstract class CustomListScrollManageActivity extends Activity{
//列表的标题
protected ArrayList<String> mListHeadItemsName = new ArrayList<String>();
//每一项checkbox的记录列表
protected LinkedList<ItemStatus> mItemsExtendData;
//列表整体标题栏
private LinearLayout mListHead = null;
//列表整体标题栏滚动条
private MyHScrollView mHScrollView = null;
//是否显示第一列
protected boolean mIsShowTextIndex = true;
//listview的适配器
protected ListNumScrollAdapter mAdapter;
//整体的根布局
protected int mRootLayout = R.layout.layout_common_sroll;
//设置是否支持长按
protected boolean mItemCanLongClick = true;
//处于长按状态true,不是长按状态false
protected boolean mLongClickStatus = false;
//checkbox的状态
protected class ItemStatus {
public boolean mIsCheckBoxVisible = false;
public boolean mIsCheckBoxSelected = false;
}
//实例化每一项checkbox的记录列表mItemsExtendData
protected LinkedList<ItemStatus> GetItemsExtendData() {
if (mItemsExtendData == null) mItemsExtendData = new LinkedList<ItemStatus>();
return mItemsExtendData;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(mRootLayout);
}
//子类继承后初始化子类数据后,需要调用这个,初始化父类。
protected void initView() {
mListHead = (LinearLayout) findViewById(R.id.surfaceManagerListHead);
mHScrollView = (MyHScrollView) mListHead.findViewById(R.id.MyHScrollView_head);
ListView listItem = (ListView)findViewById(R.id.listViewCommonFeatureItems);
//设置表头的触摸滑动事件
mHScrollView.setOnTouchListener(new ListViewAndHeadViewTouchLinstener());
listItem.setOnItemClickListener(new OnItemClickListener());
listItem.setOnItemLongClickListener(new OnItemLongClickListener());
mAdapter = new ListNumScrollAdapter(this);
listItem.setAdapter(mAdapter);
mListHeadItemsName = getReadListHeadItems();
recreateHeadControl();
initCheckBoxVilible();
setCheckBoxStatue(false);
mAdapter.notifyDataSetChanged();
}
//加载表头列表数据
protected void recreateHeadControl() {
mListHead.setFocusable(true);
mListHead.setClickable(true);
mListHead.setOnTouchListener(new ListViewAndHeadViewTouchLinstener());
TextView headIndex = (TextView)mListHead.findViewById(R.id.textIndex);
setTextParams(headIndex, mListHeadItemsName.size());
headIndex.setText("序号");
headIndex.setVisibility(mIsShowTextIndex == true?View.VISIBLE:View.GONE);
LinearLayout layout_items = (LinearLayout)mListHead.findViewById(R.id.layoutTextHeadItems);
layout_items.removeAllViews();
for (int i = 0; i < mListHeadItemsName.size(); i++) {
TextView text=new TextView(this);
text.setTextColor(getResources().getColor(R.color.list_head));
setTextParams(text, mListHeadItemsName.size());
text.setText(mListHeadItemsName.get(i));
layout_items.addView(text);
}
}
//初始化每一项的CheckBox
private void initCheckBoxVilible(){
GetItemsExtendData().clear();
for (int i = 0; i < getItemsCount(); i++) {
ItemStatus itemData = new ItemStatus();
// 插入队列
GetItemsExtendData().add(itemData);
}
}
class ListViewAndHeadViewTouchLinstener implements View.OnTouchListener {
@Override
public boolean onTouch(View arg0, MotionEvent event) {
//当在列头 和 listView控件上touch时,将这个touch的事件分发给 ScrollView
try {
mHScrollView.onTouchEvent(event);
} catch (IllegalArgumentException e) {
e.printStackTrace();
return false;
}
return false;
}
}
//抽象接口,列表标题栏
public abstract ArrayList<String> getReadListHeadItems();
//抽象接口,listview整体数据项
public abstract int getItemsCount();
/**
* 抽象接口,listview每一项数据的装载,装载返回是
* @param recordIndex
* @return ArrayList<String>
*/
public abstract ArrayList<String> getIndexDataArray(int recordIndex);
//需要每一项编辑或者增加,删除数据的抽象接口,请看具体情况自行添加
/**
* listview适配器
* @author Administrator
*
*/
public class ListNumScrollAdapter extends BaseAdapter implements OnCheckedChangeListener {
private Context mContext;
private LayoutInflater mLayoutInflater;
public ListNumScrollAdapter(Context context) {
this.mContext = context;
mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
Log.e("Show", String.valueOf(getItemsCount()));
return getItemsCount();
}
@Override
public Object getItem(int arg0) {
return null;
}
@Override
public long getItemId(int arg0) {
return arg0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
int nHeadItemCount = mListHeadItemsName.size();
ViewHolder viewHolder = null;
View view = null;
//内部类ViewHolder的作用只是用来查找ID,加载布局。提升效率的
if (convertView == null) {
viewHolder = new ViewHolder();
view = mLayoutInflater.inflate(R.layout.layout_scroll_list_item, null);
viewHolder.hscrollView = (MyHScrollView) view.findViewById(R.id.MyHScrollView_item);
viewHolder.headIndex = (TextView)view.findViewById(R.id.textIndex);
viewHolder.isSelectedCheckBox = (CheckBox) view.findViewById(R.id.checkBoxIsSelected);
view.setTag(viewHolder);
}else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
//合理分配横向滚动layout中textview的大小
TextView lisTextView[] = new TextView[nHeadItemCount];
LinearLayout layout_items = (LinearLayout)viewHolder.hscrollView.findViewById(R.id.layoutTextItems);
layout_items.removeAllViews();
for (int i = 0; i < nHeadItemCount; i++) {
TextView text=new TextView(mContext);
text.setGravity(Gravity.CENTER_VERTICAL);
setTextParams(text, nHeadItemCount);
layout_items.addView(text);
lisTextView[i] = text;
}
//列表标题栏,序号数据装载
setTextParams(viewHolder.headIndex, nHeadItemCount);
viewHolder.headIndex.setText(String.valueOf(position));
viewHolder.headIndex.setVisibility(mIsShowTextIndex == true ? View.VISIBLE : View.GONE);
//每一项横向滚动数据的装载
ArrayList<String> itemsData = getIndexDataArray(position);
for(int i=0; i < nHeadItemCount;i++) {
String value = itemsData.get(i);
lisTextView[i].setText(value);
}
//多选checkbox的状态
if (viewHolder.isSelectedCheckBox != null) {
// 设置数据
viewHolder.isSelectedCheckBox.setTag(position);
viewHolder.isSelectedCheckBox.setVisibility(mItemsExtendData.get(position).mIsCheckBoxVisible == true ? View.VISIBLE
: View.INVISIBLE);
viewHolder.isSelectedCheckBox.setChecked(mItemsExtendData.get(position).mIsCheckBoxSelected);
// 添加事件
viewHolder.isSelectedCheckBox.setOnCheckedChangeListener(this);
}
//表头列表的滚动条事件添加到listview的每一项item
mHScrollView.AddOnScrollChangedListener(new OnScrollChangedListenerImp(viewHolder.hscrollView));
return view;
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Integer nPosition = (Integer)(buttonView.getTag());
mItemsExtendData.get(nPosition.intValue()).mIsCheckBoxSelected = isChecked;
}
class OnScrollChangedListenerImp implements OnScrollChangedListener {
MyHScrollView mScrollViewArg;
public OnScrollChangedListenerImp(MyHScrollView scrollViewar) {
mScrollViewArg = scrollViewar;
}
@Override
public void onScrollChanged(int l, int t, int oldl, int oldt) {
mScrollViewArg.smoothScrollTo(l, t);
}
}
}
//listview的内部类
static class ViewHolder {
TextView headIndex;
MyHScrollView hscrollView;
CheckBox isSelectedCheckBox;
}
private class OnItemClickListener implements android.widget.AdapterView.OnItemClickListener{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
CheckBox isSelectedCheckBox = (CheckBox)view.findViewById(R.id.checkBoxIsSelected);
if (mLongClickStatus) {
//checkbox选择区域增强效果
isSelectedCheckBox.setChecked(!isSelectedCheckBox.isChecked());
return;
}
Integer nPosition = (Integer)(isSelectedCheckBox.getTag());
Toast.makeText(getApplicationContext(), String.valueOf(nPosition), Toast.LENGTH_SHORT).show();
}
}
private class OnItemLongClickListener implements android.widget.AdapterView.OnItemLongClickListener{
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,int position, long id) {
setCheckBoxStatue(true);
return true;
}
}
//控制listView checkbox控件的隐藏和显示
protected void setCheckBoxStatue(boolean isVisible){
if (isVisible) {
for (ItemStatus ItemData: GetItemsExtendData()) {
ItemData.mIsCheckBoxSelected = false;
ItemData.mIsCheckBoxVisible = true;
}
}else {
for (ItemStatus ItemData: GetItemsExtendData()) {
ItemData.mIsCheckBoxSelected = false;
ItemData.mIsCheckBoxVisible = false;
}
}
mLongClickStatus = isVisible;
mAdapter.notifyDataSetChanged();
}
@Override
public void finish(){
if (mLongClickStatus) {
setCheckBoxStatue(false);
return;
}
super.finish();
}
//设置横向滚动中layout里面textview的宽度
private void setTextParams(TextView textView, int col) {
if (col == 0)
return;
textView.setMaxLines(1);
textView.setTextSize(14);
textView.setPadding(4, 0, 4, 0);
textView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
int basicScreenWidth = metric.widthPixels; // 屏幕宽度(像素)
int basicScreenHeight = metric.heightPixels; // 屏幕高度(像素)
int screenWidth = basicScreenWidth - dip2px(this, 60);
if (col <= 3) {
textView.setWidth(screenWidth / col + 20);
} else {
if (screenWidth > basicScreenHeight) {
if (col > 5) {
textView.setWidth(screenWidth / 5 + 10);
} else {
textView.setWidth(screenWidth / col + 10);
}
} else {
textView.setWidth(screenWidth / 3 + 20);
}
}
}
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
五、看看怎样使用上面那个类,MainActivity继承CustomListScrollManageActivity
package com.org.horizontalscrollview;
import java.util.ArrayList;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Toast;
public class MainActivity extends CustomListScrollManageActivity {
private ArrayList<StudentItem> mList = new ArrayList<StudentItem>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getDataSource();
super.initView();
}
public ArrayList<StudentItem> getDataSource(){
for (int i = 0; i < 20; i++) {
int j = i;
StudentItem item1 = new StudentItem(j, "同学A", "男", 17, "高二");
mList.add(item1);
j ++ ;
StudentItem item2 = new StudentItem(j, "同学B", "女", 17, "高三");
mList.add(item2);
}
return mList;
}
@Override
public ArrayList<String> getReadListHeadItems() {
ArrayList<String> headItems = new ArrayList<String>();
headItems.add("学号");
headItems.add("姓名");
headItems.add("性别");
headItems.add("年龄");
headItems.add("年级");
return headItems;
}
@Override
public ArrayList<String> getIndexDataArray(int recordIndex) {
ArrayList<String> itemsData = new ArrayList<String>();
StudentItem item = new StudentItem();
item = mList.get(recordIndex);
for (int i = 0; i <mList.size(); i++) {
itemsData.add(String.valueOf(item.getmMunber()));
itemsData.add(item.getmName());
itemsData.add(item.getmSex());
itemsData.add(String.valueOf(item.getmAge()));
itemsData.add(item.getmGrade());
}
return itemsData;
}
@Override
public int getItemsCount() {
return mList.size();
}
}
六、主要布局layout_common_sroll
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layoutProgramManagerMainView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/surfaceManagerListHead"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#F5FFFA"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@drawable/driver"
android:paddingRight="10dp"
android:showDividers="middle" >
<TextView
android:id="@+id/textIndex"
android:layout_width="60dp"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#218868"
android:textSize="13dp" />
<com.org.scrollview.InterceptScrollContainer
android:id="@+id/scroollContainter"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:focusable="false" >
<com.org.scrollview.MyHScrollView
android:id="@+id/MyHScrollView_head"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="false"
android:scrollbars="none" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="@+id/layoutTextHeadItems"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:divider="@drawable/driver"
android:focusable="false"
android:gravity="center_vertical"
android:orientation="horizontal"
android:showDividers="middle" >
</LinearLayout>
</LinearLayout>
</com.org.scrollview.MyHScrollView>
</com.org.scrollview.InterceptScrollContainer>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="15dp"
android:visibility="gone" >
<CheckBox
android:id="@+id/checkBoxIsSelected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="invisible" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/listViewCommonFeatureItems"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</FrameLayout>
</LinearLayout>
这些选中的状态都有记下来了,后期你想怎么用就怎么用。到了这里就结束了,欢迎交流学习。