• Android自己定义组件系列【5】——进阶实践(2)


    上一篇《Android自己定义组件系列【5】——进阶实践(1)》中对任老师的《可下拉的PinnedHeaderExpandableListView的实现》前一部分进行了实现,这一篇我们来看看ExpandableListView的使用并实现剩下的部分。

    原文出处:http://blog.csdn.net/singwhatiwanna/article/details/25546871

    一、ExpandableListView的使用方法

    ExpandableListView是ListView的子类,它在普通ListView的基础上进行了扩展,适配器为ExpandableListAdapter。


    与Adapter相似的是。实现ExpandableListAdapter也有例如以下方式:

    1、扩展BaseExpandableListAdapter实现ExpandableListAdapter

    2、使用SimpleExpandableListAdapter将两个List集合包装成ExpandableListAdapter

    3、使用SimpleCursorTreeAdapter将Cursor中的数据包装成SimpleCursorTreeAdapter

    接下来用第一种方式来做个小样例。来看看ExpandableListView的使用

    		ExpandableListAdapter adapter = new BaseExpandableListAdapter() {
    			
    			@Override
    			public boolean isChildSelectable(int arg0, int arg1) {
    				// TODO Auto-generated method stub
    				return false;
    			}
    			
    			@Override
    			public boolean hasStableIds() {
    				// TODO Auto-generated method stub
    				return false;
    			}
    			
    			@Override
    			public View getGroupView(int arg0, boolean arg1, View arg2, ViewGroup arg3) {
    				// TODO Auto-generated method stub
    				return null;
    			}
    			
    			@Override
    			public long getGroupId(int arg0) {
    				// TODO Auto-generated method stub
    				return 0;
    			}
    			
    			@Override
    			public int getGroupCount() {
    				// TODO Auto-generated method stub
    				return 0;
    			}
    			
    			@Override
    			public Object getGroup(int arg0) {
    				// TODO Auto-generated method stub
    				return null;
    			}
    			
    			@Override
    			public int getChildrenCount(int arg0) {
    				// TODO Auto-generated method stub
    				return 0;
    			}
    			
    			@Override
    			public View getChildView(int arg0, int arg1, boolean arg2, View arg3,
    					ViewGroup arg4) {
    				// TODO Auto-generated method stub
    				return null;
    			}
    			
    			@Override
    			public long getChildId(int arg0, int arg1) {
    				// TODO Auto-generated method stub
    				return 0;
    			}
    			
    			@Override
    			public Object getChild(int arg0, int arg1) {
    				// TODO Auto-generated method stub
    				return null;
    			}
    		};
    能够看到BaseExpandableListApdater中的方法非常多,主要方法介绍例如以下:

    getGroupCount():返回组列表数量

    getGroupView():返回的View作为组列表项

    getChildrenCount():返回子列表项的数量

    getChildView():返回的View作为特定组、特定位置的子列表项

    package com.example.expandablelistviewtest;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.Gravity;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.AbsListView;
    import android.widget.BaseExpandableListAdapter;
    import android.widget.ExpandableListAdapter;
    import android.widget.ExpandableListView;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    public class MainActivity extends Activity {
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		ExpandableListAdapter adapter = new BaseExpandableListAdapter() {
    			
    			int[] logos = new int[] {
    				R.drawable.ic_launcher,
    				R.drawable.ic_launcher,
    				R.drawable.ic_launcher
    			};
    			
    			private String[] groupTypes = new String[]{
    				"计算机语言", "人类语言", "动物语言"	
    			};
    			
    			private String[][] childTypes = new String[][] {
    					{"Java", "C++", "C", "PHP"},
    					{"汉语", "英语", "日语", "法语"},
    					{"咕咕", "汪汪", "喵喵"}
    			};
    			
    			// 获取指定组位置、指定子列表项处的子列表项数据
    			@Override
    			public Object getChild(int groupPosition, int childPosition) {
    				return childTypes[groupPosition][childPosition];
    			}
    
    			@Override
    			public long getChildId(int groupPosition, int childPosition) {
    				return childPosition;
    			}
    
    			@Override
    			public int getChildrenCount(int groupPosition) {
    				return childTypes[groupPosition].length;
    			}
    
    			private TextView getTextView() {
    				AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
    						ViewGroup.LayoutParams.MATCH_PARENT, 64);
    				TextView textView = new TextView(MainActivity.this);
    				textView.setLayoutParams(lp);
    				textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
    				textView.setPadding(36, 0, 0, 0);
    				textView.setTextSize(20);
    				return textView;
    			}
    
    			// 该方法决定每一个子选项的外观
    			@Override
    			public View getChildView(int groupPosition, int childPosition,
    					boolean isLastChild, View convertView, ViewGroup parent) {
    				TextView textView = getTextView();
    				textView.setText(getChild(groupPosition, childPosition)
    						.toString());
    				return textView;
    			}
    
    			// 获取指定组位置处的组数据
    			@Override
    			public Object getGroup(int groupPosition) {
    				return groupTypes[groupPosition];
    			}
    
    			@Override
    			public int getGroupCount() {
    				return groupTypes.length;
    			}
    
    			@Override
    			public long getGroupId(int groupPosition) {
    				return groupPosition;
    			}
    
    			// 该方法决定每一个组选项的外观
    			@Override
    			public View getGroupView(int groupPosition, boolean isExpanded,
    					View convertView, ViewGroup parent) {
    				LinearLayout ll = new LinearLayout(MainActivity.this);
    				ll.setOrientation(0);
    				ImageView logo = new ImageView(MainActivity.this);
    				logo.setImageResource(logos[groupPosition]);
    				ll.addView(logo);
    				TextView textView = getTextView();
    				textView.setText(getGroup(groupPosition).toString());
    				ll.addView(textView);
    				return ll;
    			}
    
    			@Override
    			public boolean isChildSelectable(int groupPosition,
    					int childPosition) {
    				return true;
    			}
    
    			@Override
    			public boolean hasStableIds() {
    				return true;
    			}
    		};
    		ExpandableListView expandListView = (ExpandableListView) findViewById(R.id.list);
    		expandListView.setAdapter(adapter);
    	}
    
    }
    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context=".MainActivity" >
    	<ExpandableListView 
    	    android:id="@+id/list"
    	    android:layout_width="match_parent"
    	    android:layout_height="wrap_content"/>
    
    </RelativeLayout>

    二、代码分析

    首先看onCreate方法:

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            expandableListView = (PinnedHeaderExpandableListView) findViewById(R.id.expandablelist);
            stickyLayout = (StickyLayout)findViewById(R.id.sticky_layout);
            initData();
    
            adapter = new MyexpandableListAdapter(this);
            expandableListView.setAdapter(adapter);
    
            // 展开全部group
            for (int i = 0, count = expandableListView.getCount(); i < count; i++) {
                expandableListView.expandGroup(i);
            }
    
            expandableListView.setOnHeaderUpdateListener(this);
            expandableListView.setOnChildClickListener(this);
            expandableListView.setOnGroupClickListener(this);
            stickyLayout.setOnGiveUpTouchEventListener(this);
    
        }
    前面几行非常easy。和上面的样例差点儿一样。我们仅仅须要再关注一下initData()方法和以下的几行监听函数。

    initData()中是模拟的数据。例如以下:

        void initData() {
            groupList = new ArrayList<Group>();
            Group group = null;
            for (int i = 0; i < 3; i++) {
                group = new Group();
                group.setTitle("group-" + i);
                groupList.add(group);
            }
    
            childList = new ArrayList<List<People>>();
            for (int i = 0; i < groupList.size(); i++) {
                ArrayList<People> childTemp;
                if (i == 0) {
                    childTemp = new ArrayList<People>();
                    for (int j = 0; j < 13; j++) {
                        People people = new People();
                        people.setName("yy-" + j);
                        people.setAge(30);
                        people.setAddress("sh-" + j);
    
                        childTemp.add(people);
                    }
                } else if (i == 1) {
                    childTemp = new ArrayList<People>();
                    for (int j = 0; j < 8; j++) {
                        People people = new People();
                        people.setName("ff-" + j);
                        people.setAge(40);
                        people.setAddress("sh-" + j);
    
                        childTemp.add(people);
                    }
                } else {
                    childTemp = new ArrayList<People>();
                    for (int j = 0; j < 23; j++) {
                        People people = new People();
                        people.setName("hh-" + j);
                        people.setAge(20);
                        people.setAddress("sh-" + j);
    
                        childTemp.add(people);
                    }
                }
                childList.add(childTemp);
            }
    
        }
    接下来我们看看监听这几个监听函数

    public class MainActivity extends Activity implements
            ExpandableListView.OnChildClickListener,
            ExpandableListView.OnGroupClickListener,
            OnHeaderUpdateListener, OnGiveUpTouchEventListener {
    从Activity的继承关系上看。OnChildClickListener和OnGroupClickListener是ExpandableListView类的监听函数。

        @Override
        public boolean onGroupClick(final ExpandableListView parent, final View v,
                int groupPosition, final long id) {
    
            return false;
        }
    
        @Override
        public boolean onChildClick(ExpandableListView parent, View v,
                int groupPosition, int childPosition, long id) {
            Toast.makeText(MainActivity.this,
                    childList.get(groupPosition).get(childPosition).getName(), 1)
                    .show();
    
            return false;
        }
    再来看看OnHeaderUpdateListener,这个监听函数实际上是在重写(自己定义)的ExpandableListView中自己定义的监听。

        public void setOnHeaderUpdateListener(OnHeaderUpdateListener listener) {
            mHeaderUpdateListener = listener;
            if (listener == null) {
                return;
            }
            mHeaderView = listener.getPinnedHeader();
            int firstVisiblePos = getFirstVisiblePosition();
            int firstVisibleGroupPos = getPackedPositionGroup(getExpandableListPosition(firstVisiblePos));
            listener.updatePinnedHeader(firstVisibleGroupPos);
            requestLayout();
            postInvalidate();
        }

    getPinnedHeader()方法创建(得到)一个列表头。然后通过updatePinnedHeader方法设置当前可见的子列表元素的组名称。

    requestLayout()方法的作用是当view确定自身已经不再适合现有的区域时,该view本身调用这种方法要求parent view又一次调用他的onMeasure onLayout来对又一次设置自己位置。特别的当view的layoutparameter发生改变,而且它的值还没能应用到view上,这时候适合调用这种方法。

    postInvalidate()方法的作用是实现界面刷新。

       public interface OnHeaderUpdateListener {
            /**
             * 採用单例模式返回同一个view对象就可以
             * 注意:view必须要有LayoutParams
             */
            public View getPinnedHeader();
    
            public void updatePinnedHeader(int firstVisibleGroupPos);
        }
    从OnHeaderUpdateListener监听函数的定义上看。当触发监听后会调用两个方法的实现例如以下:

        @Override
        public View getPinnedHeader() {
            if (mHeaderView == null) {
                mHeaderView = (ViewGroup) getLayoutInflater().inflate(R.layout.group, null);
                mHeaderView.setLayoutParams(new LayoutParams(
                        LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
            }
            return mHeaderView;
        }

        @Override
        public void updatePinnedHeader(int firstVisibleGroupPos) {
            Group firstVisibleGroup = (Group) adapter.getGroup(firstVisibleGroupPos);
            TextView textView = (TextView) getPinnedHeader().findViewById(R.id.group);
            textView.setText(firstVisibleGroup.getTitle());
        }
    接下来我们须要知道什么情况下回触发这个监听函数。

       protected void refreshHeader() {
            if (mHeaderView == null) {
                return;
            }
            int firstVisiblePos = getFirstVisiblePosition();
            int pos = firstVisiblePos + 1;
            int firstVisibleGroupPos = getPackedPositionGroup(getExpandableListPosition(firstVisiblePos));
            int group = getPackedPositionGroup(getExpandableListPosition(pos));
    
            if (group == firstVisibleGroupPos + 1) {
                View view = getChildAt(1);
                if (view.getTop() <= mHeaderHeight) {
                    int delta = mHeaderHeight - view.getTop();
                    mHeaderView.layout(0, -delta, mHeaderWidth, mHeaderHeight - delta);
                }
            } else {
                mHeaderView.layout(0, 0, mHeaderWidth, mHeaderHeight);
            }
    
            if (mHeaderUpdateListener != null) {
                mHeaderUpdateListener.updatePinnedHeader(firstVisibleGroupPos);
            }
        }
    能够看到再调用refreshHeader()方法的时候会触发updatePinnerHeader方法。

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
            if (totalItemCount > 0) {
                refreshHeader();
            }
            if (mScrollListener != null) {
                mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
            }
        }
    呵呵,这下最终恍然大悟了。在onScroll方法中调用了refreshHeader,这就是说在滑动屏幕的时候OnHeaderUpdateListener监听会触发。会不断的推断是否应该改变列名称。

    快凌晨1点钟了,今天就分析到这吧。明天继续。


    再次声明一下,本文是为了学习Android自己定义组件,对任老师博客《可下拉的PinnedHeaderExpandableListView的实现》进行具体解读。假设有问题希望指出。

    原文出处:http://blog.csdn.net/singwhatiwanna/article/details/25546871













  • 相关阅读:
    Spring事务的那些坑,这里都给你总结好了!
    8 种方案解决重复提交问题!你选择哪一种呀?
    一张900w的数据表,16s执行的SQL优化到300ms?
    这 5 个开源的能挣钱的 SpringBoot 项目,真TMD香!
    邮箱mail 发送类 ASP.NET C#
    ValidationSugar表单验证框架-支持ASP.NET MVC ASP.NET WebFroM
    Jquery几个比较实用,但又让很多人忽略的几个函数
    ASP.NET MVC和WebForm 轻松实现前端和后端的双重验证 jquery.validate+ValidationSugar
    让 ASP.NET JS验证和服务端的 双验证 更简单
    ASP.NETC#通用扩展函数之TypeParse 类型转换方便多了
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/6917577.html
Copyright © 2020-2023  润新知