Android 自定義橫向滾動條聯動進階版
阿新 • • 發佈:2019-02-06
前一段時間寫了一個自定義橫向滾動條,感覺效果不怎樣好(
)。又開始改善結構,使用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的實體類沒貼出來。歡迎留言評論!