編輯:關於android開發
今天下午寫了一個分層級篩選控件,效果如下
該控件由兩部分組成:
1.上面一排的篩選標題按鈕(就是四個toggleButton,根據篩選項的數量動態追加)
2.點擊篩選按鈕彈出來的篩選內容(一個Popupwindow,它包含一個Gridview和一個Button)
需求開發點:
1.單個篩選項內容視圖的生成,也就是那個Popupwindow的內容的生成
2.主控件的實現,根據篩選項的數量動添加上面一排內容(這裡是四個篩選項),並且關聯好每一個篩選項。
1.單個彈出內容視圖的生成
我說的單個視圖指的是下面紅框框部分
首先分析,單個視圖包含什麼?
1)一個Gridview
2)一個底部Button
3)可篩選的數據List<\string>指的是A學校、B學校這些
4)其實上面的標題(大學、院系等)也歸結為單個彈出視圖的一部分,所以也得有一個變量叫title
總結: 所以單個視圖的生成至少有以上四個成員變量,所以我們的單個視圖實現如下:
package com.example.expandableview;
import java.util.ArrayList;
import java.util.List;
import com.example.expandableview.adapter.MyBaseAdapter;
import com.example.expandableview.adapter.ViewHolder;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.GridView;
import android.widget.LinearLayout;
public class ExpandleItemView extends LinearLayout {
/**顯示在toggleButton的標題文字*/
public String mTitle;
/** 底部按鈕 */
private Button mBottomBtn;
/** 展示要篩選的數據*/
private GridView mGridView;
/** 篩選的數據內容*/
private List mGridviewDatas;
public ExpandleItemView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ExpandleItemView(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public ExpandleItemView(Context context) {
this(context, null);
}
public ExpandleItemView(String title, Context context,List datas) {
this(context);
setTitle(title);
mGridviewDatas = datas;
init();
}
private void init() {
setBackgroundColor(getResources().getColor(android.R.color.white));
/**將布局inflate到此視圖中*/
LayoutInflater.from(getContext()).inflate(R.layout.expand_item_layout, this, true);
setOrientation(LinearLayout.VERTICAL);
mGridView = (GridView) findViewById(R.id.gridview);
mBottomBtn = (Button) findViewById(R.id.btn_all);
/**自己寫的通用適配器,傳入數據項和layoutid,一句話就使用了*/
mGridView.setAdapter(new MyBaseAdapter(mGridviewDatas, R.layout.gridview_item, getContext()) {
@Override
protected void convert(ViewHolder viewHolder, String t) {
viewHolder.setBtnText(R.id.item_text, t);
}
});
/**每一個子項回調給監聽者*/
mGridView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
if(mOnExpandItemClick != null)
{
mOnExpandItemClick.onItemClick(position);
}
}
});
/**底部按鈕的點擊事件回調給監聽者*/
mBottomBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(mOnExpandItemClick != null)
{
mOnExpandItemClick.onBottomClick();
}
}
});
}
public String getTitle() {
return mTitle == null ? new String() : mTitle;
}
public void setTitle(String mTitle) {
this.mTitle = mTitle;
}
public List getmGridviewDatas() {
return mGridviewDatas == null ? new ArrayList() : mGridviewDatas;
}
public void setmGridviewDatas(List mGridviewDatas) {
this.mGridviewDatas = mGridviewDatas;
}
/**
* 累加子類的高度作為自身的高度
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int cCount = getChildCount();
int desireWidth = MeasureSpec.getSize(widthMeasureSpec);
int desireHeight = 0;
for (int i = 0; i < cCount; i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
desireHeight += child.getMeasuredHeight();
}
setMeasuredDimension(desireWidth, desireHeight);
}
/**
* 點擊item事件回調給監聽者
* @author rander
*/
public interface OnExpandItemClick
{
void onItemClick(int position);
void onBottomClick();
}
private OnExpandItemClick mOnExpandItemClick;
public void setOnExpandItemClick(OnExpandItemClick onExpandItemClick) {
this.mOnExpandItemClick = onExpandItemClick;
}
}
該視圖的布局R.layout.expand_item_layout如下:
Gridview的Item布局R.layout.gridview_item,就是一個Button
分析好了,寫起代碼來還是爽歪歪吧。
2.主體控件的實現
我說的主體控件就是這個控件的功能的實現了。
首先:分析主控件包含什麼
1)有多少個篩選項List<\View>,這個View就是我們上面定義的ExpandleItemView,針對父類編程,兼容性好。也有人說所有的篩選項復用一個View就行了,是可以,但是沒有必要給自己找麻煩。
2)上面有一排按鈕,所以需要List<\View>來保存,我這裡使用的是ToggleButton,針對父類編程,用View。
3)我們點擊的時候總要記住當前篩選的是哪一項,所以我定義了一個ToggleButton記錄當前的篩選項mSelectToggleBtn
4)內容的彈出使用PopupWindow,當然需要一個變量
5)還有兩個變量,有沒有發現選中和不選中的標題顏色是不一樣的,所以定義兩個變量記錄選中的標題顏色和不選中的標題顏色。
總結:其實主控件有這也屬性就行啦,當然這裡我還定義了兩個變量記錄了PopupWindow的寬高屬性,必要性不是很大。
OK,實現代碼如下:
package com.example.expandableview;
import java.util.ArrayList;
import java.util.List;
import com.example.expandableview.ExpandleItemView.OnExpandItemClick;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.PopupWindow.OnDismissListener;
import android.widget.RelativeLayout;
import android.widget.ToggleButton;
public class ExpandableView extends LinearLayout implements OnExpandItemClick {
/** 記錄選中的ToggleButton */
private ToggleButton mSelectToggleBtn;
/** 篩選 */
private List mToggleButtons = new ArrayList<>();
/** 篩選項集合 */
private List mPopupviews;
/** popupwindow展示的寬 */
private int mDisplayWidth;
/** popupwindow展示的高 */
private int mDisplayHeight;
/** 篩選內容用PopupWindow彈出來 */
private PopupWindow mPopupWindow;
private Context mContext;
/** toggleButton正常的字體顏色 */
int mNormalTextColor = getResources().getColor(R.color.grey);
/** toggleButton被選中的類型字體顏色 */
int mSelectTextColor = Color.RED;
public ExpandableView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public ExpandableView(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public ExpandableView(Context context) {
this(context, null);
}
private void init() {
setOrientation(LinearLayout.HORIZONTAL);
mDisplayWidth = getResources().getDisplayMetrics().widthPixels;
mDisplayHeight = getResources().getDisplayMetrics().heightPixels;
mContext = getContext();
setBackgroundResource(R.drawable.choosearea_bg_right);
}
/**
* 初始化數據和布局,做的工作如下: 1.根據篩選項的數量,動態增加上面一排ToggleButton 2.設置每一個ToggleButton的監聽事件
* 3.toggleButton.setTag(i)這一句非常重要,我們取View數據都是根據這個tag取的 4.
*
* @param views
*/
public void initViews(List views) {
mPopupviews = new ArrayList<>();
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (int i = 0; i < views.size(); i++) {
ExpandleItemView view = views.get(i);
view.setOnExpandItemClick(this);
final RelativeLayout r = new RelativeLayout(mContext);
RelativeLayout.LayoutParams rl = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
r.addView(view, rl);
mPopupviews.add(r);
final ToggleButton toggleButton = (ToggleButton) inflater.inflate(R.layout.toggle_button, this, false);
toggleButton.setText(view.getTitle());
mToggleButtons.add(toggleButton);
addView(toggleButton);
toggleButton.setTag(i);
toggleButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
/** 記錄選中的ToggleButton,有了這個什麼都好辦 */
mSelectToggleBtn = toggleButton;
showPopWindow();
}
});
/**
* 點擊popupwindow外部,就隱藏popupwindow,這個r是點擊事件包裹了一個ExpandleItemView
* 如果用戶所點之處為ExpandleItemView所在范圍,點擊事件由ExpandleItemView,如果點到
* ExpandleItemView外面,則有r處理,處理方式就是收縮
*/
r.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onPressBack();
}
private void onPressBack() {
hidePopWindow();
}
});
}
}
/**
* 隱藏popupWindow,並且重置ToggleButton字體顏色
*/
private void hidePopWindow() {
if (mPopupWindow != null) {
mPopupWindow.dismiss();
}
if (mSelectToggleBtn != null) {
mSelectToggleBtn.setTextColor(mNormalTextColor);
mSelectToggleBtn.setChecked(false);
}
}
/**
* 顯示popupWindow
*/
private void showPopWindow() {
if (null == mPopupWindow) {
mPopupWindow = new PopupWindow(mPopupviews.get((int) mSelectToggleBtn.getTag()), mDisplayWidth,
mDisplayHeight);
/** 監聽popupWindow的收縮,並重置字體顏色 */
mPopupWindow.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss() {
if (mSelectToggleBtn != null) {
mSelectToggleBtn.setTextColor(mNormalTextColor);
mSelectToggleBtn.setChecked(false);
}
}
});
mPopupWindow.setAnimationStyle(R.style.PopupWindowAnimation);
mPopupWindow.setFocusable(true);
mPopupWindow.setOutsideTouchable(true);
mPopupWindow.setBackgroundDrawable(new BitmapDrawable());
} else {
mPopupWindow.setContentView(mPopupviews.get((int) mSelectToggleBtn.getTag()));
}
if (mPopupWindow.isShowing()) {
hidePopWindow();
} else {
/** 顯示的時候,設為選中顏色 */
mSelectToggleBtn.setTextColor(mSelectTextColor);
mPopupWindow.showAsDropDown(mToggleButtons.get(0), 0, 0);
}
}
/**
* Item項選中的回調 注意Tag的使用 篩選項視圖是根據tag拿的,因為mSelectToggleBtn的tag就是視圖的索引
* mSelectToggleBtn顯示篩選的內容
*/
@Override
public void onItemClick(int position) {
hidePopWindow();
if (null != mSelectToggleBtn) {
int selectBtnIndex = (int) mSelectToggleBtn.getTag();
mSelectToggleBtn
.setText(((ExpandleItemView) (((RelativeLayout) mPopupviews.get(selectBtnIndex)).getChildAt(0)))
.getmGridviewDatas().get(position));
}
}
/**
* 底部按鈕點擊的回調 mSelectToggleBtn顯示篩選的內容
*/
@Override
public void onBottomClick() {
hidePopWindow();
if (null != mSelectToggleBtn) {
int selectBtnIndex = (int) mSelectToggleBtn.getTag();
mSelectToggleBtn
.setText((((ExpandleItemView) (((RelativeLayout) mPopupviews.get(selectBtnIndex)).getChildAt(0)))
.getTitle()));
}
}
}
上面使用的單個ToggleButton的視圖R.layout.toggle_button如下:
接下來就是使用了,使用的布局如下:
Activity代碼如下:
package com.example.expandableview;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
private ExpandableView mExpandableView;
private Map mExpandleItemViews;
private String[] mColleages = { "A學校", "B學校", "C學校", "D學校", "E學校", "F學校", "G學校", "H學校", "I學校", "J學校" };
private String[] mDepartments = { "A系", "B系", "C系", "D系", "E系", "F系", "G系", "H系" , "I系" };
private String[] mProfessions = { "A專業", "B專業", "C專業" , "D專業" , "E專業" , "F專業" };
private String[] mClasses = { "A班", "B班", "C班", "D班" , "E班" };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mExpandableView = (ExpandableView) findViewById(R.id.expandview);
mExpandleItemViews = new LinkedHashMap<>();
//不要問我為什麼這麼用,因為我想用LinkedHashMap
mExpandleItemViews.put("大學", new ExpandleItemView("大學", this, Arrays.asList(mColleages)));
mExpandleItemViews.put("院系", new ExpandleItemView("院系", this, Arrays.asList(mDepartments)));
mExpandleItemViews.put("專業", new ExpandleItemView("專業", this, Arrays.asList(mProfessions)));
mExpandleItemViews.put("班級", new ExpandleItemView("班級", this, Arrays.asList(mClasses)));
mExpandableView.initViews(new ArrayList<>(mExpandleItemViews.values()));
}
}
Android-現場保護,android-現場現場保護 當一個活動進入到了停止的狀態,是有可能被系統回收的,我們都學過Activity的生命周期 當活動處於onPaus
Android自定義控件:下拉菜單的實現與優化 下拉菜單 美團首頁類似的下拉彈出菜單工程中經常遇到的控件,不同工程中菜單條目的類型與數量也不一樣 所以需要根據實際需要填
Android開發之自定義組件和接口回調,android回調說到自定義控件不得不提的就是接口回調,在Android開發中接口回調用的還是蠻多的。在這篇博客開始的時候呢,我
Android 中即時聊天或者後台任務需要發送消息的一種解決方案. 在即時聊天中可能會存在一個隱藏的Bug,這個Bug根據手機的網速和性能有關系,比