編輯:關於Android編程
能夠使頭部懸停的listview在項目中是經常用到的,例如qq的好友列表或者地區選擇。
先不多說,看效果圖:(懶得上gif圖了)
這裡借鑒了別人的核心代碼,我做了一些分析。
主要是使用PinnedSectionListView來替換listview。
這裡的PinnedSectionListView是別人的。我們主要看如何使用這個PinnedSectionListView以及如何適配數據進去。
先看項目結構圖:
其中:PinnedSectionListView是原封不動借鑒的別人的
其他的則是適配listview和數據的類<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxoMiBpZD0="1activity">1,activity
activity裡面很簡單了
public class IndexActivity extends AppCompatActivity {
private PinnedSectionListView pinned_section_list;
private IndexAdapter indexAdapter;
private List data;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//實例化擁有懸停頭的控件
pinned_section_list = (PinnedSectionListView) findViewById(R.id.pinned_section_list);
//模擬數據
data = new TestData().initData();
//初始化適配器
indexAdapter = new IndexAdapter(this, data);
//添加適配器
pinned_section_list.setAdapter(indexAdapter);
}
}
public class CityBean {
private int cityId;//城市id
private String cityName;//城市名
private int superiorId;//上級城市id
private List subordinateList;//下級城市集合
//忽略get/set方法
}
public class TestData {
private List data;
public List initData() {
data = new ArrayList<>();
for (int j = 1; j < 11; j++) {
List beijingList = new ArrayList<>();
for (int i = 1; i < 11; i++) {
CityBean cityBean = new CityBean();
cityBean.setCityId(i + 10);
cityBean.setCityName("北京" + i + "區");
beijingList.add(cityBean);
}
CityBean cityBean = new CityBean();
cityBean.setCityId(1);
cityBean.setCityName("北京" + j);
cityBean.setSubordinateList(beijingList);
data.add(cityBean);
List shanghaiList = new ArrayList<>();
for (int i = 1; i < 11; i++) {
CityBean cityBean1 = new CityBean();
cityBean1.setCityId(i + 20);
cityBean1.setCityName("上海" + i + "區");
shanghaiList.add(cityBean1);
}
CityBean cityBean1 = new CityBean();
cityBean1.setCityId(2);
cityBean1.setCityName("上海" + j);
cityBean1.setSubordinateList(shanghaiList);
data.add(cityBean1);
List shenzhenList = new ArrayList<>();
for (int i = 1; i < 11; i++) {
CityBean cityBean2 = new CityBean();
cityBean2.setCityId(i + 20);
cityBean2.setCityName("深圳" + i + "區");
shenzhenList.add(cityBean2);
}
CityBean cityBean2 = new CityBean();
cityBean2.setCityId(3);
cityBean2.setCityName("深圳" + j);
cityBean2.setSubordinateList(shenzhenList);
data.add(cityBean2);
}
return data;
}
}
public class Item {
public static final int ITEM = 0;//判斷是否是普通item
public static final int SECTION = 1;//判斷是否是需要置頂懸停的item
public final int type;//外部傳入的類型,ITEM或者SECTION
public final CityBean cityBean;//外部傳入的數據,這裡我們將它寫成城市實體類,可以任意更換
public int sectionPosition;//頭標記,一般用父數據的id標記
public int listPosition;//集合標記,一般用自身的id標記
public Item(int type, CityBean cityBean) {
this.type = type;
this.cityBean = cityBean;
}
//獲得其中保存的數據
public CityBean getCityBean() {
return cityBean;
}
}
Item類用來保存外部傳進來的數據和設置該數據的類型是屬於懸停頭還是普通item。
懸停listview的適配器必須實現PinnedSectionListView中的接口:PinnedSectionListAdapter和android原生接口:SectionIndexer
public class IndexAdapter extends BaseAdapter implements PinnedSectionListView.PinnedSectionListAdapter, SectionIndexer {
//為了區分頭部的背景顏色,也可換成其他方式。例如:布局樣式
private static final int[] COLORS = new int[]{
R.color.green_light, R.color.orange_light,
R.color.blue_light, R.color.red_light};
private List data;//外部傳進來的原始數據
private List- items;//這個才是真正顯示的list
private Context context;
private Item[] sections;//頭標記數組
public IndexAdapter(Context context, List
data) {
this.data = data;
this.context = context;
initSection();
}
//初始化顯示數據
private void initSection() {
items = new ArrayList<>();
sections = new Item[data.size()];
//數據准備
for (int i = 0; i < data.size(); i++) {
//添加頭信息,將頭標記和數據傳入
Item section = new Item(Item.SECTION, data.get(i));
section.sectionPosition = data.get(i).getCityId();//將父類城市id作為頭id傳入,因為父類id沒有上級城市了,所以傳自身id
section.listPosition = data.get(i).getCityId();//傳入自身id,將當前城市id作為普通id傳入
//頭標記組中城市id的標記相對應放入該城市的Item實例
sections[section.sectionPosition] = section;
items.add(section);
//當前城市的下級城市
for (int j = 0; j < data.get(i).getSubordinateList().size(); j++) {
//下級城市為普通item,所以傳入Item.ITEM
Item item = new Item(Item.ITEM, data.get(i).getSubordinateList().get(j));
item.sectionPosition = data.get(i).getCityId();//將父類城市id作為頭id傳入,證明該普通id下的城市屬於哪個父類城市
item.listPosition = data.get(i).getSubordinateList().get(j).getCityId();//傳入自身id,將當前城市id作為普通id傳入
items.add(item);
}
}
}
/*************************
* 以下是PinnedSectionListView的重寫方法
*************************************************/
//當前view是否屬於固定的item
@Override
public boolean isItemViewTypePinned(int viewType) {
return viewType == Item.SECTION;
}
/*************************
* 以下是adapter的重寫方法
*************************************************/
//傳入視圖類型的個數,表示有幾種視圖類型
//PinnedSectionListView中如果發現adapter的getViewTypeCount<2會拋出異常
@Override
public int getViewTypeCount() {
return 2;
}
//返回每一個視圖的類型
@Override
public int getItemViewType(int position) {
return getItem(position).type;
}
@Override
public int getCount() {
return items.size();
}
@Override
public Item getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
View v;
ViewHolder vh;
Item item = items.get(position);// 從集合中獲取當前行的數據
if (view == null) {
// 說明當前這一行不是重用的
// 加載行布局文件,產生具體的一行
v = View.inflate(context, R.layout.item, null);
// 創建存儲一行控件的對象
vh = new ViewHolder();
// 將該行的控件全部存儲到vh中
vh.tvName = (TextView) v.findViewById(R.id.text_text);
v.setTag(vh);// 將vh存儲到行的Tag中
} else {
v = view;
// 取出隱藏在行中的Tag--取出隱藏在這一行中的vh控件緩存對象
vh = (ViewHolder) view.getTag();
}
// 從ViewHolder緩存的控件中改變控件的值
// 這裡主要是避免多次強制轉化目標對象而造成的資源浪費
vh.tvName.setText(item.getCityBean().getCityName());
if (item.type == Item.SECTION) {
v.setBackgroundColor(parent.getResources().getColor(COLORS[item.sectionPosition % COLORS.length]));
}
return v;
}
// 存儲一行中的控件(緩存作用)---避免多次強轉每行的控件
class ViewHolder {
TextView tvName;
}
/************************
* 以下是SectionIndexer接口的重寫方法
******************************************/
//返回一個對象數組代表列表的部分,用於來顯示頭
//這裡返回的Item[]是裝的頭的部分
@Override
public Item[] getSections() {
return sections;
}
//給定的索引部分數組內的部分對象,返回在適配器部分的起始位置。
@Override
public int getPositionForSection(int sectionIndex) {
//以免拋出異常
if (sectionIndex >= sections.length) {
sectionIndex = sections.length - 1;
}
//返回當前頭集合的頭id
return sections[sectionIndex].listPosition;
}
//給定一個適配器內的位置,返回相應的索引部分數組內的部分對象。
@Override
public int getSectionForPosition(int position) {
if (position >= getCount()) {
position = getCount() - 1;
}
//返回當前item中保存的頭id
return getItem(position).sectionPosition;
}
}
整個項目的代碼就是這些,有興趣的可以看看PinnedSectionListView中是如何實現的。我看了一部分,因為時間關系沒有繼續研究了。
問題概述 在編輯框輸入內容時會彈出軟鍵盤,而手機屏幕區域有限往往會遮住輸入界面,我們先看一下問題效果圖: 輸入用戶名和密碼時,系統會彈出鍵盤,造成系統鍵盤會擋住
先看看效果圖:問題: 1、下拉列表(因為還沒看到這裡...) 2、標題欄顯示問題 3、按鈕的 Enable 設置 ....
起因: 最近在做一個新聞APP,看到現在的新聞客戶端頂端都有個熱點新聞輪播。思路:viewpager可以用來顯示圖片,並且可以提供滑動,15年(不知記錯沒)新出的TabL
Sensor概述 基於Android的設備有內置的傳感器,測量運動,方向,和各種環境條件。這些傳感器能夠提供原始數據的高精度和准確度,並且是有用的如果你想要監測裝置、定位