1. 程式人生 > >Android 自定義橫向滾動條聯動進階版

Android 自定義橫向滾動條聯動進階版

前一段時間寫了一個自定義橫向滾動條,感覺效果不怎樣好(

)。又開始改善結構,使用setScrollView寫了一個聯動進階版。標題的滾動條和內容資料item資料滾動條都可以聯動滾動。豎向是兩個listview,但是是使用全域性的豎向滾動條來滾動。所以橫向與豎向、單擊、長按時間都不會受到影響。長按會橫向移動到最右端,顯示checkbx。先看效果圖。
1、實現效果圖


2、實現聯動效果的,自定義繼承自HorizontalScrollView的SyncHorizontalScrollView滾動條
package com.org.scrollview;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.HorizontalScrollView;
/**
* @Description:這個類也是從網上找的參考
*/
public class SyncHorizontalScrollView extends HorizontalScrollView {
	
	private View mView;
	
	public SyncHorizontalScrollView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}
	
	public SyncHorizontalScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}
 
	protected void onScrollChanged(int l, int t, int oldl, int oldt) {
		super.onScrollChanged(l, t, oldl, oldt);
		//設定控制元件滾動監聽,得到滾動的距離,然後讓傳進來的view也設定相同的滾動具體
		if(mView!=null) {
			mView.scrollTo(l, t);
		}
	}
	
	/**
	* 設定跟它聯動的view
	* @param view
	*/
	public void setScrollView(View view) {
		mView = view;
	}
}

3、通用的聯動效果的封裝類,供需要此效果類繼承即可。CustomListScrollManageActivity
package com.org.horizontalscrollview;

import java.util.ArrayList;
import java.util.LinkedList;
import com.org.scrollview.SyncHorizontalScrollView;
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.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.ListAdapter;
import android.widget.ListView;
import android.widget.ScrollView;
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 SyncHorizontalScrollView mListHScrollView = null;
	//是否顯示第一列
	protected boolean mIsShowTextIndex = true;
	//listview的右邊介面卡
	protected ListRightAdapter mRightAdapter;
	//listview的左邊介面卡
	protected ListLeftAdapter mLeftAdapter;
	//處於長按狀態true,不是長按狀態false
	protected boolean mLongClickStatus = false;
	//右邊的listview
	protected ListView mrightListView;
	//左邊的listview
	protected ListView mleftListView;
	//整體的根佈局
	protected int mRootLayout = R.layout.layout_common_sroll;
	
	//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() {
		mListHScrollView = (SyncHorizontalScrollView) findViewById(R.id.listRightHScrollView);
		SyncHorizontalScrollView listHeadHScrollView = (SyncHorizontalScrollView) findViewById(R.id.listHeadHScrollView);
		//設定右邊兩個橫向滾動條的聯動滑動
		mListHScrollView.setScrollView(listHeadHScrollView);
		listHeadHScrollView.setScrollView(mListHScrollView);
		
		mrightListView = (ListView)findViewById(R.id.rightListView);
		mleftListView = (ListView)findViewById(R.id.leftListView);
		
		//設定右邊的監聽事件
		mrightListView.setOnItemClickListener(new OnItemClickListener());
		mrightListView.setOnItemLongClickListener(new OnItemLongClickListener());
		
		mListHeadItemsName = getReadListHeadItems();
		
		mRightAdapter = new ListRightAdapter(this);
		mrightListView.setAdapter(mRightAdapter);
		
		mLeftAdapter = new ListLeftAdapter(this);
		mleftListView.setAdapter(mLeftAdapter);
		
		recreateHeadControl();
		
		initCheckBoxVilible();
		
		setCheckBoxStatue(false);
		
		refreshListView();
	}
	
	//重新整理列表
	protected void refreshListView(){
		//禁止了listview的自帶的滾動,需要手動計算listview高度,使用滾動條欄滾動
		SetListViewHeightBasedOnChildren(mleftListView);
		SetListViewHeightBasedOnChildren(mrightListView);
		mRightAdapter.notifyDataSetChanged();
		mLeftAdapter.notifyDataSetChanged();		
	}
	
	//載入表頭列表資料
	protected void recreateHeadControl() {
		TextView headIndex = (TextView)findViewById(R.id.textIndex);
		setTextParams(headIndex, mListHeadItemsName.size());
		headIndex.setText("序號");
		headIndex.setVisibility(mIsShowTextIndex == true?View.VISIBLE:View.GONE);
		
		LinearLayout layout_items = (LinearLayout)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);
		}		
	}
	
	//抽象介面,列表標題欄
	public abstract ArrayList<String> getReadListHeadItems();
	//抽象介面,listview整體資料項
	public abstract int getItemsCount();
	/**
	 * 抽象介面,listview每一項資料的裝載,裝載返回是
	 * @param recordIndex
	 * @return  ArrayList<String>
	 */
	public abstract ArrayList<String> getIndexDataArray(int recordIndex);
	////////////////////////////////////////////////////////////
	//需要每一項編輯或者增加,刪除資料的抽象介面,請看具體情況自行新增
	
	
	
	/**
	 * 左邊的介面卡
	 * @author Administrator
	 *
	 */
	public class ListLeftAdapter extends BaseAdapter{
		private Context mContext;
		private LayoutInflater mLayoutInflater;
		
		public ListLeftAdapter(Context context) {
			this.mContext = context;
			mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		}
		
		@Override
		public int getCount() {
			return getItemsCount();
		}

		@Override
		public Object getItem(int position) {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public long getItemId(int position) {
			// TODO Auto-generated method stub
			return 0;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			ViewHolder viewHolder = null;
			View view = null;
			//內部類ViewHolder的作用只是用來查詢ID,載入佈局。提升效率的
			if (convertView == null) {
				viewHolder = new ViewHolder();
				view = mLayoutInflater.inflate(R.layout.layout_scroll_list_item_left, null);
				viewHolder.headIndex = (TextView)view.findViewById(R.id.textIndex);
				view.setTag(viewHolder);
			}else {
				view = convertView;
				viewHolder = (ViewHolder) view.getTag();
			}
			
			//列表標題欄,序號資料裝載
			viewHolder.headIndex.setText(String.valueOf(position));
			viewHolder.headIndex.setVisibility(mIsShowTextIndex == true ? View.VISIBLE : View.GONE);		
			return view;
		}
		
	}
	
	/**
	 * 右邊介面卡
	 * @author Administrator
	 *
	 */
	public class ListRightAdapter extends BaseAdapter implements OnCheckedChangeListener {
		private Context mContext;
		private LayoutInflater mLayoutInflater;
		
		public ListRightAdapter(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_right, null);
				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)view.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;
			}
			
			//每一項橫向滾動資料的裝載
			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);
			}
			
			return view;
		}

		@Override
		public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
			Integer nPosition = (Integer)(buttonView.getTag());
			mItemsExtendData.get(nPosition.intValue()).mIsCheckBoxSelected = isChecked;
		}

	}	

	//listview的內部類
	private class ViewHolder {
		TextView headIndex;
		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);
			
			if (mListHScrollView != null) {
				mListHScrollView.post(new Runnable() { 
			        public void run() { 
			        	mListHScrollView.fullScroll(ScrollView.FOCUS_RIGHT); 
			        } 
			}); 
			}
			return false;
		}
	}
	
	//控制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;
		refreshListView();
	}
	
	@Override
	public void finish(){
		if (mLongClickStatus) {
			setCheckBoxStatue(false);
			return;
		}
		super.finish();
	}
	
	//手動計算listview的高度
	private void SetListViewHeightBasedOnChildren(ListView listView) {
		if (listView == null) return;
		ListAdapter listAdapter = listView.getAdapter();
		if (listAdapter == null) return;
		int nTotalHeight = 0;
		for (int i = 0; i < listAdapter.getCount(); i++) {
			View listItem = listAdapter.getView(i, null, listView);
			listItem.measure(0, 0);
			nTotalHeight += listItem.getMeasuredHeight();
		}
		
		ViewGroup.LayoutParams params = listView.getLayoutParams();
		params.height = nTotalHeight + (listView.getDividerHeight()*(listAdapter.getCount()-1));
	}
		
	//設定橫向滾動中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);
	}
}

4、看怎麼繼承實現上面類的資料介面MainActivity
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", "男", 18, "高二");
        	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();
	}
}
5、主要的是還有一個佈局,實現效果關鍵
<?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/HeadListLayout"
                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.SyncHorizontalScrollView
                        android:id="@+id/listHeadHScrollView"
                        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.SyncHorizontalScrollView>
                </LinearLayout>
            </LinearLayout>

            <ScrollView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fillViewport="true" >

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:orientation="vertical" >

                    <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:divider="@drawable/driver"
                            android:orientation="horizontal"
                            android:showDividers="middle" >

                            <LinearLayout
                                android:layout_width="60dp"
                                android:layout_height="match_parent"
                                android:divider="@drawable/driver"
                                android:orientation="vertical"
                                android:showDividers="end" >

                                <ListView
                                    android:id="@+id/leftListView"
                                    android:layout_width="match_parent"
                                    android:layout_height="wrap_content" >
                                </ListView>
                            </LinearLayout>

                            <com.org.scrollview.SyncHorizontalScrollView
                                android:id="@+id/listRightHScrollView"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:scrollbars="@null" >

                                <LinearLayout
                                    android:layout_width="match_parent"
                                    android:layout_height="match_parent"
                                    android:orientation="vertical" >

                                    <ListView
                                        android:id="@+id/rightListView"
                                        android:layout_width="match_parent"
                                        android:layout_height="wrap_content" >
                                    </ListView>
                                </LinearLayout>
                            </com.org.scrollview.SyncHorizontalScrollView>
                        </LinearLayout>
                    </RelativeLayout>
                </LinearLayout>
            </ScrollView>
        </LinearLayout>
    </FrameLayout>

</LinearLayout>

此外還有次要的兩個listview的item的佈局沒貼出來,還有一個StudentItem的實體類沒貼出來。歡迎留言評論!