編輯:關於Android編程
1、概述
在android中我們平日經常用listview、gridview控件來制作數據不固定的表格,一般都是頭列表格頭固定,底下listview展示可變數據,然而在工作中我碰到了一個需求:上下滑動時頭列固定,左右滑動時頭行固定的,流量了很多網站都沒有找到合適的,於是自己想了一個解決方案。
馬上上效果圖,有這個效果需要的同仁繼續往下看
2、思路
我們看到的效果好像是一個既可以左右滑動又能上下滑動的ListView,其實不然,這個要用單純的一個ListView或者ScrollView實現非常困難,所以我選擇了把它們組合起來,組合方式如下:
最左上角的TextView是不動的,當左右滑動時候,第一列固定,右邊上下兩個ScrollView實現聯動;當上下滑動時,頭部第一行不動,下面兩個ListView實現聯動就行了。
3、代碼實現
首先是主界面的布局:avtivity_main
由於頭部標題的ScrollView一般是不能去主動滑動的,所以要攔截掉ScrollView的touch事件,代碼詳細大家都懂,這裡為了方便一並附出:
package com.lunge.mydifdirtable.view; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.HorizontalScrollView; /** * Created by Binglun on 7/13 0013 17:26 */ public class NoScrollHorizontalScrollView extends HorizontalScrollView { public NoScrollHorizontalScrollView(Context context) { super(context); } public NoScrollHorizontalScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public NoScrollHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onInterceptHoverEvent(MotionEvent event) { return false; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { return false; } }看到這裡,大家就明白當左右滑動時,是下面的ScrollView帶著上面的ScrollView一起滑動的,實現方式是再自定義一個ScrollView,用監聽者模式,在自己滑動的回調代碼裡onScrollStateChange,調用頂部ScrollView的onScroll方法,實現同步滑動;代碼如下:
package com.lunge.mydifdirtable.view; import android.content.Context; import android.util.AttributeSet; import android.widget.HorizontalScrollView; /** * Created by Lunger on 7/11 0011 15:47 */ public class LinkedHorizontalScrollView extends HorizontalScrollView { private LinkScrollChangeListener listener; public LinkedHorizontalScrollView(Context context) { super(context); } public LinkedHorizontalScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public LinkedHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public void setMyScrollChangeListener(LinkScrollChangeListener listener){ this.listener = listener; } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if(null != listener) listener.onscroll(this, l, t, oldl, oldt); } /** * 控制滑動速度 */ @Override public void fling(int velocityY) { super.fling(velocityY / 2); } public interface LinkScrollChangeListener { void onscroll(LinkedHorizontalScrollView view, int l, int t, int oldl, int oldt); } }
package com.lunge.mydifdirtable; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.AbsListView; import android.widget.HorizontalScrollView; import android.widget.ListView; import com.lunge.mydifdirtable.adapter.LvInfoAdapter; import com.lunge.mydifdirtable.adapter.LvNameAdapter; import com.lunge.mydifdirtable.view.LinkedHorizontalScrollView; import com.lunge.mydifdirtable.view.NoScrollHorizontalScrollView; public class MainActivity extends AppCompatActivity { private NoScrollHorizontalScrollView sv_normalgoods_title;//不可滑動的頂部左側的ScrollView private LinkedHorizontalScrollView sv_normalgoods_detail;//底部左側的ScrollView private ListView lv_normalgoodname;//底部左側的ListView private ListView lv_normalgood_info;//底部右側的ListView boolean isLeftListEnabled = false; boolean isRightListEnabled = false; private LvNameAdapter mLvNormalNameAdapter; private LvInfoAdapter mLvNormalInfoAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initAdapter(); } private void initView() { sv_normalgoods_title = (NoScrollHorizontalScrollView)findViewById(R.id.sv_title); sv_normalgoods_detail = (LinkedHorizontalScrollView)findViewById(R.id.sv_good_detail); lv_normalgoodname = (ListView) findViewById(R.id.lv_goodname); lv_normalgood_info = (ListView)findViewById(R.id.lv_good_info); combination(lv_normalgoodname, lv_normalgood_info, sv_normalgoods_title, sv_normalgoods_detail); } private void initAdapter() { mLvNormalNameAdapter = new LvNameAdapter(this); mLvNormalInfoAdapter = new LvInfoAdapter(this); lv_normalgoodname.setAdapter(mLvNormalNameAdapter); lv_normalgood_info.setAdapter(mLvNormalInfoAdapter); } private void combination(final ListView lvName, final ListView lvDetail, final HorizontalScrollView title, LinkedHorizontalScrollView content) { /** * 左右滑動同步 */ content.setMyScrollChangeListener(new LinkedHorizontalScrollView.LinkScrollChangeListener() { @Override public void onscroll(LinkedHorizontalScrollView view, int x, int y, int oldx, int oldy) { title.scrollTo(x, y); } }); /** * 上下滑動同步 */ // 禁止快速滑動 lvName.setOverScrollMode(ListView.OVER_SCROLL_NEVER); lvDetail.setOverScrollMode(ListView.OVER_SCROLL_NEVER); //左側ListView滾動時,控制右側ListView滾動 lvName.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { //這兩個enable標志位是為了避免死循環 if (scrollState == SCROLL_STATE_TOUCH_SCROLL) { isRightListEnabled = false; isLeftListEnabled = true; } else if (scrollState == SCROLL_STATE_IDLE) { isRightListEnabled = true; } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { View child = view.getChildAt(0); if (child != null && isLeftListEnabled) { lvDetail.setSelectionFromTop(firstVisibleItem, child.getTop()); } } }); //右側ListView滾動時,控制左側ListView滾動 lvDetail.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (scrollState == SCROLL_STATE_TOUCH_SCROLL) { isLeftListEnabled = false; isRightListEnabled = true; } else if (scrollState == SCROLL_STATE_IDLE) { isLeftListEnabled = true; } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { View c = view.getChildAt(0); if (c != null && isRightListEnabled) { lvName.setSelectionFromTop(firstVisibleItem, c.getTop()); } } }); } }代碼不多也比較容易理解,這裡就不多述。就介紹到此;
等等,博主,裡面的adapter代碼呢???
這也要附啊,好吧:
LvNameAdapter:
package com.lunge.mydifdirtable.adapter; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.lunge.mydifdirtable.R; /** * Created by Binglun on 7/13 0013 16:05 */ public class LvNameAdapter extends BaseAdapter { private Context context; public LvNameAdapter(Context context) { this.context = context; } @Override public int getCount() { return 100; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if(convertView == null){ holder = new ViewHolder(); convertView = LayoutInflater.from(context).inflate(R.layout.item_lv_good_name, null); holder.tv_goodname = (TextView) convertView.findViewById(R.id.tv_name); convertView.setTag(holder); }else{ holder = (ViewHolder) convertView.getTag(); } holder.tv_goodname.setText("iPone" + (position+4) + "s"); return convertView; } class ViewHolder{ TextView tv_goodname; } }
對應布局文件:
LvInfoAdapter:
package com.lunge.mydifdirtable.adapter; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import com.lunge.mydifdirtable.R; /** * Created by Lunger on 7/13 0013 16:06 */ public class LvInfoAdapter extends BaseAdapter { private Context context; public LvInfoAdapter(Context context) { this.context = context; } @Override public int getCount() { return 100; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { holder = new ViewHolder(); convertView = LayoutInflater.from(context).inflate(R.layout.item_lv_good_info, null); holder.tv_barcode = (TextView) convertView.findViewById(R.id.tv_barcode); holder.tv_category = (TextView) convertView.findViewById(R.id.tv_category); holder.tv_spec = (TextView) convertView.findViewById(R.id.tv_spec); holder.tv_unit = (TextView) convertView.findViewById(R.id.tv_unit); holder.tv_supplyer = (TextView) convertView.findViewById(R.id.tv_supplyer); holder.tv_sale_money = (TextView) convertView.findViewById(R.id.tv_sale_money); holder.tv_income_money = (TextView) convertView.findViewById(R.id.tv_income_money); holder.tv_keep = (TextView) convertView.findViewById(R.id.tv_keep); holder.tv_intime = (TextView) convertView.findViewById(R.id.tv_intime); holder.tv_online = (ImageView) convertView.findViewById(R.id.iv_online); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } if (position < 10) { holder.tv_barcode.setText("1001200660" + position); } else { holder.tv_barcode.setText("100120066" + position); } holder.tv_category.setText("類型" + position); holder.tv_spec.setText("規格" + position); holder.tv_unit.setText("個"); holder.tv_supplyer.setText("供應商" + position); holder.tv_sale_money.setText("價格" + position); holder.tv_keep.setText("1年"); holder.tv_intime.setText("2016-03-21"); holder.tv_income_money.setText("進貨價" + position); return convertView; } } class ViewHolder { TextView tv_barcode; TextView tv_category; TextView tv_spec; TextView tv_unit; TextView tv_supplyer; TextView tv_sale_money; TextView tv_income_money; TextView tv_keep; TextView tv_intime; ImageView tv_online; }對應布局文件:
曾在網上找了一些關於CoordinatorLayout的教程,大部分文章都是把CoordinatorLayout、AppbarLayout、CollapsingToolb
0.簽名java -Xmx2048m -jar out/host/linux-x86/framework/signapk.jar -w build/target/prod
目前市面上的應用,貌似除了微信和手Q都會比較擔心被用戶或者系統(廠商)殺死問題。本文對 Android 進程拉活進行一個總結。Android 進程拉活包括兩個層面:A.
今天寫一個餅圖自定義View的文章。由於公司的項目需要用到餅圖,UI給的設計圖和自己找的一個餅圖框架的標題位置不符,所以就自己畫了一個。1,使用預覽PieChart mC