編輯:關於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的使用如此簡單(Android)
曾在網上找了一些關於CoordinatorLayout的教程,大部分文章都是把CoordinatorLayout、AppbarLayout、CollapsingToolb
android OTA升級包制作
0.簽名java -Xmx2048m -jar out/host/linux-x86/framework/signapk.jar -w build/target/prod
Android中的各種保活1
目前市面上的應用,貌似除了微信和手Q都會比較擔心被用戶或者系統(廠商)殺死問題。本文對 Android 進程拉活進行一個總結。Android 進程拉活包括兩個層面:A.
Android PieChart 餅圖控件
今天寫一個餅圖自定義View的文章。由於公司的項目需要用到餅圖,UI給的設計圖和自己找的一個餅圖框架的標題位置不符,所以就自己畫了一個。1,使用預覽PieChart mC