Android custom hierarchical Filtering Control
This afternoon I wrote a hierarchical filtering control. The effect is as follows:
The control consists of two parts:
1. The filter title button in the above row (four togglebuttons, dynamically appended based on the number of filtering items)
2. Click the filter content (A Popupwindow that contains a Gridview and a Button)
Requirement Development point:
1. Generate the content view of a single filter item, that is, the content of the Popupwindow.
2. Implement the main control, add the content in the above row (four filtering items here) based on the quantity of filtering items, and associate each filtering item.
1. Generate a single pop-up content View
A single view refers to the section in the red box below.
First, what does a single view contain?
1) A Gridview
2) A bottom Button
3) The List of filtered data <\ string> refers to schools A and B.
4) In fact, the title above (university, department, etc.) also comes down to a part of a single pop-up view, so there must also be a variable called title
Conclusion: the generation of a single view contains at least four member variables. Therefore, the implementation of a single view is as follows:
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 {/** the title text displayed in toggleButton */public String mTitle;/** the bottom Button */private Button mBottomBtn; /** display the data to be filtered */private GridView mGridView;/** filtered data content */private List
MGridviewDatas; public ExpandleItemView (Context context, AttributeSet attrs, int defStyleAttr) {super (context, attrs, expiration);} 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);/** Add the layout inflate to this view */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);/** use a self-written universal adapter to input data items and layoutid. */mGridView is used in one sentence. setAdapter (new MyBaseAdapter
(MGridviewDatas, R. layout. gridview_item, getContext () {@ Override protected void convert (ViewHolder viewHolder, String t) {viewHolder. setBtnText (R. id. item_text, t) ;}});/** calls back each subitem to the listener */mGridView. setOnItemClickListener (new OnItemClickListener () {@ Override public void onItemClick (AdapterView
Parent, View view, int position, long id) {if (mOnExpandItemClick! = Null) {mOnExpandItemClick. onItemClick (position) ;}});/** Click Event at the bottom of the button to callback to the listener */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;}/*** the height of the accumulate subclass is used as its own height */@ 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);}/*** click the item event to callback to the listener * @ author rander */public interface OnExpandItemClick {void onItemClick (int position ); void onBottomClick ();} private OnExpandItemClick mOnExpandItemClick; public void setOnExpandItemClick (OnExpandItemClick onExpandItemClick) {this. mOnExpandItemClick = onExpandItemClick ;}}
The layout of this view is as follows:
The layout of items in the Gridview is R. layout. gridview_item, which is a Button.
After analysis, write the code.
2. Implementation of the subject Control
The main control I mentioned is the implementation of the control function.
First, analyze what the main control contains
1) How many filtering items are listed <\ View>. This View is the ExpandleItemView defined above. It is compatible with the parent class programming. Some people also say that all the filtering items can reuse a View. Yes, but there is no need to bother yourself.
2) There is a row of buttons above, so List <\ View> is required for saving. Here I am using ToggleButton. For parent class programming, View is used.
3) When we click, we always remember which filter item is currently selected. So I defined a ToggleButton to record the Current Filter item mSelectToggleBtn.
4) PopupWindow is used for content pop-up. Of course, a variable is required.
5) There are two other variables. Do you find that the color of the selected and unselected titles is different? Therefore, define the color of the selected titles and the color of the unselected titles for the two variables.
Summary: in fact, this is also the property of the main control. Of course, here I have defined two variables to record the width and height attributes of PopupWindow, which is not necessary.
OK. The implementation code is as follows:
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 {/** record the selected ToggleButton */private ToggleButton mSelectToggleBtn;/** filter */private List
MToggleButtons = new ArrayList <> ();/** filter Item Set */private List
MPopupviews;/** popupwindow display width */private int mDisplayWidth;/** popupwindow display height */private int mDisplayHeight; /** pop up the filtering content using PopupWindow */private PopupWindow mPopupWindow; private Context mContext;/** normal font color of toggleButton */int mNormalTextColor = getResources (). getColor (R. color. gray);/** toggleButton selected font Color */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);}/*** initialize the data and layout, and do the following: 1. based on the number of filtering items, the top row of ToggleButton 2 is dynamically added. set the monitoring event for each ToggleButton * 3. toggleButton. the setTag (I) clause is very important. We retrieve the View data according to this 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. layoutPar Ams. 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 v Oid onClick (View v) {/** record the selected ToggleButton. It is easy to do anything with this */mSelectToggleBtn = toggleButton; showPopWindow ();}}); /*** click the outside of popupwindow to hide the popupwindow. This r is a click event that wraps an ExpandleItemView * If the user points to the range of ExpandleItemView, the click event is set to ExpandleItemView, if a point is placed out of * ExpandleItemView, r processing is available. The processing method is to contract */r. setOnClickListener (new OnClickListener () {@ Override public void onClick (View v) {onPressBack ();} private void onPress Back () {hidePopWindow () ;}}) ;}/ *** hide popupWindow and reset ToggleButton font color */private void hidePopWindow () {if (mPopupWindow! = Null) {mPopupWindow. dismiss ();} if (mSelectToggleBtn! = Null) {mSelectToggleBtn. setTextColor (mNormalTextColor); mSelectToggleBtn. setChecked (false) ;}}/*** display popupWindow */private void showPopWindow () {if (null = mPopupWindow) {mPopupWindow = new PopupWindow (mPopupviews. get (int) mSelectToggleBtn. getTag (), mDisplayWidth, mDisplayHeight);/** listen to the shrinking of popupWindow and reset the font color */mPopupWindow. setOnDismissListener (new OnDismissListener () {@ Override publi C 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 (mPopupWindo W. isShowing () {hidePopWindow ();} When else {/** is displayed, set it to the selected color */mSelectToggleBtn. setTextColor (mSelectTextColor); mPopupWindow. showAsDropDown (mToggleButtons. get (0), 0, 0) ;}/ *** the callback for the selected Item. Note that the filter Item view for Tag usage is obtained based on tag, because the tag of mSelectToggleBtn is the view Index * mSelectToggleBtn displays the filtered content */@ 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) ;}}/*** click the callback mSelectToggleBtn at the bottom of the button to display the filtered content */@ Override public void onBottomClick () {hidePopWindow (); if (null! = MSelectToggleBtn) {int selectBtnIndex = (int) mSelectToggleBtn. getTag (); mSelectToggleBtn. setText (ExpandleItemView) (RelativeLayout) mPopupviews. get (selectBtnIndex )). getChildAt (0 ))). getTitle ()));}}}
The preceding view of a single ToggleButton R. layout. toggle_button is as follows:
The following figure shows the layout:
The Activity code is as follows:
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 school", "B school", "C school", "D school", "E school", "F school ", "G school", "H school", "I school", "J school"}; private String [] mments ments = {"A", "B ", "C", "D", "E", "F", "G", "H", "I "}; private String [] mProfessions = {"A major", "B major", "C major", "D major", "E Major", "F Major "}; private String [] mClasses = {"Class A", "Class B", "Class C", "Class D", "Class E "}; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); mExpandableView = (ExpandableView) findViewById (R. id. expandview); mExpandleItemViews = new LinkedHashMap <> (); // do not ask why I use it because I want to use LinkedHashMap mExpandleItemViews. put ("", new ExpandleItemView ("", this, Arrays. asList (mColleages); mExpandleItemViews. put ("Faculty", new ExpandleItemView ("Faculty", this, Arrays. asList (mments ments); mExpandleItemViews. put ("professional", new ExpandleItemView ("professional", this, Arrays. asList (mProfessions); mExpandleItemViews. put ("class", new ExpandleItemView ("class", this, Arrays. asList (mClasses); mExpandableView. initViews (new ArrayList <> (mExpandleItemViews. values ()));}}