一级关联列表android_android 列表对话框 实现关联列表 - CSDN
  • 最近做级联操作,一级菜单和二级菜单的显示,发现Android官方自带了

         最近需要用到级联操作,一级菜单和二级菜单的显示,发现Android官方自带了一个控件,ExpandableListView,学了一下用法,还好比较简单,当然也要先写一个自定义的适配器去继承BaseExpandableListAdapter,并实现方法

    public class MyAdapter extends BaseExpandableListAdapter{
    
    	@Override
    	public int getGroupCount() {
    		return 0;
    	}
    
    	@Override
    	public int getChildrenCount(int groupPosition) {
    		return 0;
    	}
    
    	@Override
    	public Object getGroup(int groupPosition) {
    		return null;
    	}
    
    	@Override
    	public Object getChild(int groupPosition, int childPosition) {
    		return null;
    	}
    
    	@Override
    	public long getGroupId(int groupPosition) {
    		return 0;
    	}
    
    	@Override
    	public long getChildId(int groupPosition, int childPosition) {
    		return 0;
    	}
    
    	@Override
    	public boolean hasStableIds() {
    		return false;
    	}
    
    	@Override
    	public View getGroupView(int groupPosition, boolean isExpanded,
    			View convertView, ViewGroup parent) {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public View getChildView(int groupPosition, int childPosition,
    			boolean isLastChild, View convertView, ViewGroup parent) {
    		return null;
    	}
    
    	@Override
    	public boolean isChildSelectable(int groupPosition, int childPosition) {
    		return false;
    	}
    
    }
         一个个看,getGroupCount就是返回一级菜单的数目,getChildrenCount就是返回当前一级菜单下的二级菜单的数目,getGroup就是返回groupPosition所关联的data,getChild则是返回两个参数下关联的data,getGroupId直接返回groupPosition,getChildId如果没有要求也是直接返回childPosition,getGroupView和getChildView都是设置view显示的样子,可以在xml中自定义,也可以直接在代码中实例化。剩下的hasStableIds和isChildSelectable直接返回true就行。

        如果要展示的数据比较简单只有一项的话可以直接使用list集合,但是如果数据比较多,比如一个子view中同时显示内容和时间两个属性,就需要在list集合中嵌套一个map集合。在使用集合的时候要考虑将group的数据和child的数据关联起来,这样才能联动显示。先假设一个需求,比如qq的联系人界面,一级界面时好友分组,只有一个textview,二级界面做的简陋一点,一个imageview和一个textview,那么我们先开始写布局文件

    res/layout/group.xml 一级菜单的布局

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
        <TextView
            android:id="@+id/group_text"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_marginLeft="25dp"
            android:textColor="#000000"
            android:textSize="18sp" />
    
    </LinearLayout>
    res/layout/child.xml  二级菜单的布局

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center_vertical"
        android:orientation="horizontal" >
        
        <ImageView 
            android:id="@+id/child_img"
            android:layout_marginLeft="20dp"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:src="@drawable/ic_launcher"/>
        
        <TextView 
            android:textColor="#111111"
            android:id="@+id/child_txt"
            android:layout_marginLeft="20dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            />
    
    </LinearLayout>
    

    在自定义的适配器中实例化

    public class MyAdapter extends BaseExpandableListAdapter{
    	
    	private Context mContext;
    	private List<String> mGroups;
    	private List<List<Map<String, Object>>> mChilds;
    	
    	//构造函数中传入上下文对象,group的data,child的data
    	public MyAdapter(Context context,List<String> group,List<List<Map<String, Object>>> child){
    		this.mContext = context;
    		this.mGroups = group;
    		this.mChilds = child;
    	}
    
    	@Override
    	public int getGroupCount() {
    		return mGroups.size();
    	}
    
    	@Override
    	public int getChildrenCount(int groupPosition) {
    		return mChilds.get(groupPosition).size();
    	}
    
    	@Override
    	public Object getGroup(int groupPosition) {
    		return mGroups.get(groupPosition);
    	}
    
    	@Override
    	public Object getChild(int groupPosition, int childPosition) {
    		return mChilds.get(groupPosition).get(childPosition);
    	}
    
    	@Override
    	public long getGroupId(int groupPosition) {
    		return groupPosition;
    	}
    
    	@Override
    	public long getChildId(int groupPosition, int childPosition) {
    		return childPosition;
    	}
    
    	@Override
    	public boolean hasStableIds() {
    		return true;
    	}
    
    	@Override
    	public View getGroupView(int groupPosition, boolean isExpanded,
    			View convertView, ViewGroup parent) {
    		LinearLayout mLinearGroup = (LinearLayout) LayoutInflater
    				.from(mContext).inflate(R.layout.group, null);
    		TextView grouptext = (TextView) mLinearGroup.findViewById(R.id.group_text);
    		String text = mGroups.get(groupPosition);
    		grouptext.setText(text);
    		return mLinearGroup;
    	}
    
    	@Override
    	public View getChildView(int groupPosition, int childPosition,
    			boolean isLastChild, View convertView, ViewGroup parent) {
    		LinearLayout mLinearChild = (LinearLayout) LayoutInflater
    				.from(mContext).inflate(R.layout.child, null);
    		ImageView childimg= (ImageView) mLinearChild.findViewById(R.id.child_img);
    		Bitmap bitmap = (Bitmap) mChilds.get(groupPosition).get(childPosition).get("image");
    		childimg.setImageBitmap(bitmap);
    		TextView childtext = (TextView) mLinearChild.findViewById(R.id.child_txt);
    		String text = (String) mChilds.get(groupPosition).get(childPosition).get("text");
    		childtext.setText(text);
    		return mLinearChild;
    	}
    
    	@Override
    	public boolean isChildSelectable(int groupPosition, int childPosition) {
    		return true;
    	}
    
    }
    

    然后在activity中进行调用

    public class MainActivity extends Activity {
    
    	private ExpandableListView mListView;
    	private MyAdapter mAdapter;
    	List<String> group = null;
    	List<List<Map<String, Object>>> child = null;
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		mListView = (ExpandableListView) findViewById(R.id.expand);
    		initData();
    		mAdapter = new MyAdapter(getApplicationContext(), group, child);
    		mListView.setAdapter(mAdapter);
    //		mListView.setGroupIndicator(null);  //设置箭头消失
    	}
    
    	/**
    	 * 传入测试数据,实际获取方法类似
    	 */
    	private void initData() {
    		group = new ArrayList<String>();
    		group.add("我的好友");
    		group.add("我的家人");
    		group.add("我的同学");
    		Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
    		child = new ArrayList<List<Map<String,Object>>>();
    		for (int i = 0; i < group.size(); i++) {
    			List<Map<String, Object>> lists = new ArrayList<Map<String,Object>>();
    			for (int j = 0; j < 6; j++) {
    				Map<String, Object> map = new HashMap<String, Object>();
    				map.put("image",bitmap );
    				map.put("text", group.get(i)+j);
    				lists.add(map);
    			}
    			child.add(lists);
    		}
    	}
    }

    效果如下:


    源码下载链接:http://download.csdn.net/detail/u013926110/8973617


    展开全文
  • 通常我们在外卖或者商城app会看到竖排二级列表的界面,点击左边列表的分类菜单,右边列表则会显示对应分类下的列表内容,这篇博文将对该功能的实现归纳和整理。 首先看下效果图: 在第个页面选择最多三个标签...

    通常我们在外卖或者商城app会看到竖排二级列表的界面,点击左边列表的分类菜单,右边列表则会显示对应分类下的列表内容,这篇博文将对该功能的实现归纳和整理。

    首先看下效果图:

    在第一个页面选择最多三个标签,将书局塞到数组里返回上一个页面,然后就可以按照需求完成一系列操作。

    下面说下实现步骤:

    1.首先分析界面,是两个等比宽的列表,推荐使用recyclerview,右上角用来记录选择的标签个数,点击即可把数据返回上一个页面,未选择则返回空数组。

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="40dp">
    
            <TextView
                android:id="@+id/main_tv"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:gravity="center_vertical"
                android:text="确定(0/3)"
                android:textSize="16sp"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:paddingRight="10dp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="选择页面"
                android:textSize="18sp"
                android:layout_centerInParent="true"
                />
        </RelativeLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">
    
            <android.support.v7.widget.RecyclerView
                android:id="@+id/main_recyclerviewAll"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" />
    
            <View
                android:layout_width="1dp"
                android:layout_height="match_parent"
                android:background="@color/colorPrimaryDark" />
    
            <android.support.v7.widget.RecyclerView
                android:id="@+id/main_recyclerviewDetail"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" />
        </LinearLayout>
    </LinearLayout>
    

    2.绘制列表item布局,因为就是简单的一个文字,只放一个居中的TextView,由于RecyclerView默认没有分隔线,我们在下面再放条高度为1px的view

    item_recyclerview.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:id="@+id/item_recyclerview_ll">
    
        <TextView
            android:id="@+id/item_recyclerview_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="textview"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="15dp"
            />
        <View
            android:layout_width="match_parent"
            android:layout_height="1px"
            android:background="#e3e3d3"
            android:layout_marginTop="15dp"/>
    
    </LinearLayout>

    3.新建FirstActivity,界面放个跳转至选择界面MainActivity的Button和用于显示从选择界面返回的标签数组的TextView

    activity_first.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <Button
            android:id="@+id/first_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="去选择界面" />
    
        <TextView
            android:id="@+id/first_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
    </LinearLayout>

    4.在选择界面MainActivity中,首先初始化控件。

    tv = findViewById(R.id.main_tv);
    recyclerviewAll = findViewById(R.id.main_recyclerviewAll);
    recyclerviewDetail = findViewById(R.id.main_recyclerviewDetail);
    LinearLayoutManager layout = new LinearLayoutManager(this);
    LinearLayoutManager layout1 = new LinearLayoutManager(this);
    recyclerviewAll.setLayoutManager(layout);
    recyclerviewDetail.setLayoutManager(layout1);

    5.设置列表数据bean,isFirst为是否选中的状态boolean值

    package com.fantasychong.doublechecklisttest;
    
    import java.io.Serializable;
    
    /*
     *Crated by yedona on 2018/9/6
     */
    public class ListBean implements Serializable {
    
        private String name;
        private boolean isSelect;
    
        public ListBean(String name, boolean isSelect) {
            this.name = name;
            this.isSelect = isSelect;
        }
    
        public boolean isSelect() {
            return isSelect;
        }
    
        public void setSelect(boolean select) {
            isSelect = select;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

    5.设置左列表(一级)的数据,因为第一个数据标签默认选中,所以我们设置isSelect为true。

    /**
     * 设置左列表数据
     */
    private void initAllList() {
        allList = new ArrayList<>();
        AllListBean bean = new AllListBean("英雄联盟", true);
        allList.add(bean);
        AllListBean bean1 = new AllListBean("仙剑奇侠传", false);
        allList.add(bean1);
        AllListBean bean2 = new AllListBean("大航海时代", false);
        allList.add(bean2);
        AllListBean bean3 = new AllListBean("太阁立志传", false);
        allList.add(bean3);
        AllListBean bean4 = new AllListBean("战国无双", false);
        allList.add(bean4);
        AllListBean bean5 = new AllListBean("三国志", false);
        allList.add(bean5);
        AllListBean bean6 = new AllListBean("最终幻想", false);
        allList.add(bean6);
        AllListBean bean7 = new AllListBean("幻想传说", false);
        allList.add(bean7);
    }

    6.设置左右列表的通用adapter,这里推荐继承BaseQuickApdater,精简易操作。

    package com.fantasychong.doublechecklisttest;
    
    import android.content.Context;
    import android.graphics.Color;
    import android.support.annotation.Nullable;
    import android.widget.TabHost;
    import com.chad.library.adapter.base.BaseQuickAdapter;
    import com.chad.library.adapter.base.BaseViewHolder;
    import java.util.List;
    
    /*
     *Crated by yedona on 2018/9/6
     */
    public class ListAdapter extends BaseQuickAdapter<AllListBean, BaseViewHolder> {
    
        private final Context context;
        private final List<AllListBean> data;
    
        public ListAdapter (Context context, @Nullable List<AllListBean> data) {
            super(R.layout.item_recyclerview, data);
            this.context= context;
            this.data= data;
        }
    
        @Override
        protected void convert(BaseViewHolder helper, AllListBean item) {
            helper.setText(R.id.item_recyclerview_tv, item.getName())
                    .setBackgroundColor(R.id.item_recyclerview_ll, item.isSelect()? Color.WHITE: Color.GRAY);
        }
    }
    

    在convert方法中设置是否选中后的背景颜色,选中设为白色white,反之设为灰色gray。

    7.把数据塞到左recyclerView中,这样左列表可以呈现我们的塞进去的数据。

    adapterAll = new ListAdapter (MainActivity.this, allList);
    recyclerviewAll.setAdapter(adapterAll);

    8.设置左列表的点击事件,当选中时标签会变为白色,并且上个选中标签会设置成未选中状态,即为灰色。注意这里要添加notifyDataSetChanged方法通知adapter刷新。

    adapterAll.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
            if (perPosition != position) {
                allList.get(perPosition).setSelect(false);
                allList.get(position).setSelect(true);
                adapterAll.notifyDataSetChanged();
                perPosition = position;
            }
        }
    });

    9.这样就完成了左列表显示并选中未选中的功能实现,接下来我们配置右(二级)列表。

    我们初衷是进入页面时,左列表直接显示数据,右列表也要显示左列表的第一个分类下的数据,更改左列表标签,右列表的数据也会随之更改。

    所以我们先把左列表第一个标签下的内容塞到右列表中让它呈现。

    adapterAll.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
            if (perPosition != position) {
                allList.get(perPosition).setSelect(false);
                allList.get(position).setSelect(true);
                adapterAll.notifyDataSetChanged();
                //设置右列表数据
                initDetailList(position);
                adapterDetail.notifyDataSetChanged();
                perPosition = position;
            }
        }
    });
    adapterDetail = new ListAdapter(MainActivity.this, detailList);
    recyclerviewDetail.setAdapter(adapterDetail);

    10.这样进入界面两个列表都会显示数据了,接下来做二级列表的选中和取消选中功能,因为二级列表要多选,所以可设置多个标签同时选中状态,同时把选中标签塞到一个checklist中,用于返回上个页面FirstActivity中,记着实时更新右上角的选中个数文本。

    adapterDetail.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
            if (detailList.get(position).isSelect()){
                checkList.remove(detailList.get(position).getName());
            }else{
                if (checkList.size()== 3) {
                    Toast.makeText(MainActivity.this, "最多只能选择三个", Toast.LENGTH_SHORT).show();
                    return;
                }
                checkList.add(detailList.get(position).getName());
            }
            detailList.get(position).setSelect(!detailList.get(position).isSelect());
            adapterDetail.notifyDataSetChanged();
        }
    });

    11.接下来要做他们的联动,当一级列表点击时,二级列表数据会更新,所以我们先清空二级列表数据list,再把一级列表position对应的数据塞到二级列表数据list,把已选中标签塞到一个checklist中,用于返回上一个页面FirstActivity中。

    /**
     * 设置右列表数据
     */
    private void initDetailList(int position) {
        detailList.clear();
        switch (position) {
            case 0:
                ListBean bean = new ListBean("暗夜猎手薇恩", false);
                detailList.add(bean);
                ListBean bean1 = new ListBean("暴走萝莉金克丝", false);
                detailList.add(bean1);
                ListBean bean2 = new ListBean("皮城女警凯瑟琳", false);
                detailList.add(bean2);
                ListBean bean3 = new ListBean("放逐之刃锐雯", false);
                detailList.add(bean3);
                break;
            case 1:
                ListBean bean4 = new ListBean("李逍遥", false);
                detailList.add(bean4);
                ListBean bean5 = new ListBean("赵灵儿", false);
                detailList.add(bean5);
                ListBean bean6 = new ListBean("林月如", false);
                detailList.add(bean6);
                ListBean bean7 = new ListBean("阿奴", false);
                detailList.add(bean7);
                break;
            case 2:
                ListBean bean8 = new ListBean("拉斐尔卡斯特路", false);
                detailList.add(bean8);
                ListBean bean9 = new ListBean("丽璐阿歌特", false);
                detailList.add(bean9);
                ListBean bean10 = new ListBean("李华梅", false);
                detailList.add(bean10);
                ListBean bean11 = new ListBean("赫德拉姆约阿奇姆柏格斯统", false);
                detailList.add(bean11);
                ListBean bean12 = new ListBean("蒂雅瓦曼恰斯卡", false);
                detailList.add(bean12);
                break;
            case 3:
                ListBean bean13 = new ListBean("丰臣秀吉", false);
                detailList.add(bean13);
                ListBean bean14 = new ListBean("织田信长", false);
                detailList.add(bean14);
                ListBean bean15 = new ListBean("真田幸村", false);
                detailList.add(bean15);
                ListBean bean16 = new ListBean("武田信玄", false);
                detailList.add(bean16);
                ListBean bean17 = new ListBean("本多忠胜", false);
                detailList.add(bean17);
                break;
            case 4:
                ListBean bean18 = new ListBean("上杉谦信", false);
                detailList.add(bean18);
                break;
            case 5:
                ListBean bean19 = new ListBean("赵云", false);
                detailList.add(bean19);
                break;
            case 6:
                ListBean bean20 = new ListBean("萨菲罗斯", false);
                detailList.add(bean20);
                break;
            case 7:
                ListBean bean21 = new ListBean("达尔斯", false);
                detailList.add(bean21);
                break;
            default:
                break;
        }
    }

    12.把initDetailList方法放到一级列表的onitemclicklistener中,同时一级列表切换时,清空二级列表的已选中标签数组checklist。

    adapterAll.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
            if (perPosition != position) {
                allList.get(perPosition).setSelect(false);
                allList.get(position).setSelect(true);
                adapterAll.notifyDataSetChanged();
                //设置右列表数据
                initDetailList(position);
                checkList.clear();
                tv.setText("确定(0/3)");
                adapterDetail.notifyDataSetChanged();
                perPosition = position;
            }
        }
    });

    13.这下联动已经完成,设置右上角个数文本的点击事件,使用setResult方法传递checklist。

    tv.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent= new Intent();
            intent.putExtra("list", checkList.toString());
            setResult(1, intent);
            finish();
        }
    });

    14.在FirstActivity中接受list并显示在textview上,可以根据实际需求做相应操作。

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (data== null){
            return;
        }
        if (requestCode== 1){
            tv.setText(data.getStringExtra("list"));
            Log.d("listlistlist", data.getStringExtra("list"));
        }
    }

    至此全部完成,Demo附上。

    资源下载

     

     

     

     

    展开全文
  • XX公司 -》刘XX 生产部 -》何XX 策划组 -》吴XX 技术员 刘X 实习生 -》李XX 宣传组 ...然后关联一个数据库。我想知道怎么分 各种类。。 跪求思路。
  • ExpandableListView是个用于垂直滚动展示二级列表的视图,与ListView不同的是它可以展示二级列表,分组可以 单独展开子选项。这些选项数据是通过ExpandableListView关联的。创建布局文件&lt;...

    ExpandableListView是一个用于垂直滚动展示二级列表的视图,与ListView不同的是它可以展示二级列表,分组可以 单独展开子选项。这些选项数据是通过ExpandableListView关联的。

    创建布局文件

    <ExpandableListView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">
                </ExpandableListView>

    上述是简单的布局文件使用,同时也可以添加如下属性:

    android:childDivider:制定各组内子类表项之间的分隔条,分隔表是一条直线
    android:childDivider:制定各组内子类表项之间的分隔条,分隔表是一条直线
    android:childIndicator:显示在子列表左边的Drawable对象,可以是一个图像
    android:childIndicatorEnd:子列表指示符的结束约束位置
    android:childIndicatorLeft:子列表指示符的左边约束位置
    android:childIndicatorRight:子列表指示符的右边约束位置
    android:childIndicatorStart:子列表指示符的开始约束位置
    android:groupIndicator:显示在组列表旁边的DrawAble对象,可以是一个图像
    android:indicatorEnd:组列表指示符的结束约束位置
    android:indicatorLeft:组列表指示符的左边约束位置
    android:indicatorRight:组列表指示符的右边约束位置
    android:indicatorStart:组列表指示符的开始约束位置

    父项布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="8dp"
        android:paddingTop="8dp">
        <TextView
            android:id="@+id/tv_item_list_group_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="40dp"
            android:text="文件夹"
            android:textAppearance="@style/TextAppearance.AppCompat.Title" />
    </LinearLayout>

    子项布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp"
        android:orientation="horizontal"
        android:paddingLeft="16dp">
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="25dp"
            android:layout_margin="8dp">
    
            <View
                android:id="@+id/v_list_item_priority"
                android:layout_width="5dp"
                android:layout_height="18dp"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                android:background="@color/colorWhite" />
    
            <TextView
                android:id="@+id/tv_list_item_list_name"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_centerVertical="true"
                android:layout_marginLeft="5dp"
                android:layout_toRightOf="@id/v_list_item_priority"
                android:gravity="center_vertical"
                android:text="清单名"
                android:textSize="20sp" />
    
            <TextView
                android:id="@+id/tv_list_item_stuffs"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_alignParentRight="true"
                android:layout_marginRight="10dp"
                android:gravity="bottom"
                android:text="0"
                android:textSize="16dp" />
        </RelativeLayout>
    </LinearLayout>


    ExpandableAdapter数据适配器

    实现ExpandableAdapter的三种方式

    1、拓展BaseExpandableListAdapter实现ExpandableAdapter

    2、使用simpleExpandableListAdapter将两个list集合包装成ExpandableAdapter

    本demo使用第一种方式实现数据适配器,由于父项和子项都有一些点击事件,因此使用了接口回调的方式实现。

    public class ListGroupExpandableAdapter extends BaseExpandableListAdapter {
        private static final String TAG = ListGroupExpandableAdapter.class.getSimpleName();
        private java.util.List<ListGroup> listGroups;
        private java.util.List<java.util.List<List>> lists;
        private OnChildClickListener mOnChildClickListener;
        private OnParentClickListener mOnParentClickListener;
    
        public ListGroupExpandableAdapter(java.util.List<ListGroup> listGroups, java.util.List<java.util.List<List>> lists) {
            this.listGroups = listGroups;
            this.lists = lists;
        }
    
        public void setOnChildClickListener(OnChildClickListener onChildClickListener){
            mOnChildClickListener = onChildClickListener;
        }
    
        public void setOnParentClickListener(OnParentClickListener onParentClickListener){
            mOnParentClickListener = onParentClickListener;
        }
    
        @Override
        public int getGroupCount() {  //获取父项数量
            return listGroups.size();
        }
    
        @Override
        public int getChildrenCount(int i) {  //获取子项数量
            return lists.get(i).size();
        }
    
        @Override
        public Object getGroup(int i) {  //获取父项
            return listGroups.get(i);
        }
    
        @Override
        public Object getChild(int i, int i1) {//获取子项
            return lists.get(i).get(i1);
        }
    
        @Override
        public long getGroupId(int i) {  //获取父项位置
            return i;
        }
    
        @Override
        public long getChildId(int i, int i1) {  //获取子项位置
            return i1;
        }
    
        @Override
        public boolean hasStableIds() {  
            return true;
        }
    
        @Override
        public View getGroupView(final int i, boolean b, View view, ViewGroup viewGroup) {  //获取父项布局
            GroupViewHolder groupViewHolder;
            if(view == null) {
                view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_group_group_item, null);
                groupViewHolder = new GroupViewHolder();
                groupViewHolder.view = view;
                groupViewHolder.listGroupNameTv = view.findViewById(R.id.tv_item_list_group_name);
                view.setTag(groupViewHolder);
            }else {
                groupViewHolder = (GroupViewHolder) view.getTag();
            }
            Log.d(TAG, "getGroupView: " + listGroups.get(i).getName());
            groupViewHolder.listGroupNameTv.setText(listGroups.get(i).getName());
            if(mOnParentClickListener != null) {
                groupViewHolder.view.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        mOnParentClickListener.onParentClickListener(view, i);
                    }
                });
                groupViewHolder.view.setOnLongClickListener(new View.OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View view) {
                        mOnParentClickListener.onParentLongClickListener(view, i);
                        return true;
                    }
                });
            }
            return view;
        }
    
        @Override
        public View getChildView(final int i, final int i1, boolean b, View convertView, ViewGroup viewGroup) {  //获取子项布局
            ChildViewHolder childViewHolder;
            View view;
            if(convertView == null) {
                view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item, null);
                childViewHolder = new ChildViewHolder();
                childViewHolder.view = view;
                childViewHolder.priorityColor = view.findViewById(R.id.v_list_item_priority);
                childViewHolder.listNameTv = view.findViewById(R.id.tv_list_item_list_name);
                childViewHolder.stuffNumTv = view.findViewById(R.id.tv_list_item_stuffs);
                view.setTag(childViewHolder);
            }else {
                view = convertView;
                childViewHolder = (ChildViewHolder) view.getTag();
            }
            switch (lists.get(i).get(i1).getPriority()) {
                case 1:
                    childViewHolder.priorityColor.setBackgroundColor(childViewHolder.priorityColor.getResources().getColor(R.color.colorBule));
                    break;
                case 2:
                    childViewHolder.priorityColor.setBackgroundColor(childViewHolder.priorityColor.getResources().getColor(R.color.colorYellow));
                    break;
                case 3:
                    childViewHolder.priorityColor.setBackgroundColor(childViewHolder.priorityColor.getResources().getColor(R.color.colorAccent));
                    break;
                default:
                    childViewHolder.priorityColor.setBackgroundColor(childViewHolder.priorityColor.getResources().getColor(R.color.colorWhite));
                    break;
            }
            childViewHolder.listNameTv.setText(lists.get(i).get(i1).getName());
            childViewHolder.stuffNumTv.setText(String.valueOf(lists.get(i).get(i1).getStuffs()));
            if(mOnChildClickListener != null) {
                childViewHolder.view.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        mOnChildClickListener.onChildClickListener(view, i, i1);
                    }
                });
                childViewHolder.view.setOnLongClickListener(new View.OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View view) {
                        mOnChildClickListener.onChildLongClickListener(view, i, i1);
                        return true;
                    }
                });
            }
            return view;
        }
    
        @Override
        public boolean isChildSelectable(int i, int i1) {
            return true;
        }
    
        public interface OnChildClickListener {   //子项点击事件
            void onChildClickListener(View view, int parentPos, int childPos);
            void onChildLongClickListener(View view, int parentPos, int childPos);
        }
    
        public interface OnParentClickListener{   //父项点击事件
            void onParentClickListener(View view, int parentPos);
            void onParentLongClickListener(View view, int parentPos);
        }
    
        class GroupViewHolder {
            View view;
            TextView listGroupNameTv;
        }
    
        class ChildViewHolder {
            View view;
            View priorityColor;
            TextView listNameTv;
            TextView stuffNumTv;
        }
    }

    使用ExpandableListView

    传入父项数据和子项数据,创建数据适配器,然后在expandableListView中设置数据适配器。

    public void showAllLists(final java.util.List<ListGroup> listGroups, final java.util.List<java.util.List<List>> lists) {
            try{
                mListGroups = listGroups;
                mLists = lists;
                mExpandableAdapter = new ListGroupExpandableAdapter(mListGroups, mLists);
                mExpandableAdapter.setOnChildClickListener(new ListGroupExpandableAdapter.OnChildClickListener() {
                    @Override
                    public void onChildClickListener(View view, int parentPos, int childPos) {
                        try{
                            showListDetail(lists.get(parentPos).get(childPos));
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
    
                    @Override
                    public void onChildLongClickListener(View view, final int parentPos, final int childPos) {
                        try{
                            getActivity().runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    onChildLongClick(parentPos, childPos);
                                }
                            });
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                });
                mExpandableAdapter.setOnParentClickListener(new ListGroupExpandableAdapter.OnParentClickListener() {
                    @Override
                    public void onParentClickListener(View view, final int parentPos) {
                        try{
                            getActivity().runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    if(mExpandableListView.isGroupExpanded(parentPos)) {
                                        mExpandableListView.collapseGroup(parentPos);
                                    }else {
                                        mExpandableListView.expandGroup(parentPos);
                                    }
                                }
                            });
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
    
                    @Override
                    public void onParentLongClickListener(View view, final int parentPos) {
                        try{
                            getActivity().runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    onParentLongClick(parentPos);
                                }
                            });
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                });
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mExpandableListView.setAdapter(mExpandableAdapter);
                        mExpandableListView.setOnScrollListener(new AbsListView.OnScrollListener() {
                            @Override
                            public void onScrollStateChanged(AbsListView absListView, int i) {
    
                            }
    
                            @Override
                            public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                                View firstView = absListView.getChildAt(firstVisibleItem);
                                if (firstVisibleItem == 0 && (firstView == null || firstView.getTop() == 0)) {
                                    mSwipeRefreshLayout.setEnabled(true);
                                } else {
                                    mSwipeRefreshLayout.setEnabled(false);
                                }
                            }
                        });
                        int count = mExpandableListView.getCount();
                        for (int i = 0; i < count; i++) {   //默认展开所有父项
                            mExpandableListView.expandGroup(i);
                        }
                        mExpandableListView.setVisibility(View.VISIBLE);
                    }
                });
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    最后实现的效果如下:

    groupIndicator父项列表指示,也可以设置为不显示或者自定义指示器:

     mExpandableListView.setGroupIndicator(null);
     mExpandableListView.setGroupIndicator(getActivity().getResources().getDrawable(R.drawable.group_indicator));

    指示器布局:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@mipmap/packup" android:state_expanded="true"/>
        <item android:drawable="@mipmap/unfold"/>
    </selector>




    展开全文
  • Android学习路线指南

    2018-02-28 16:17:05
    看到篇文章中提到“最近几年国内的初级Android程序员已经很多了,但是中高级的Android技术人才仍然稀缺“,这的确不假,从我在百度所进行的一些面试来看,找个适合的高级Android工程师的确不容易,一般需要进行...

    前言

    看到一篇文章中提到“最近几年国内的初级Android程序员已经很多了,但是中高级的Android技术人才仍然稀缺“,这的确不假,从我在百度所进行的一些面试来看,找一个适合的高级Android工程师的确不容易,一般需要进行大量的面试才能挑选出一个比较满意的。为什么中高级Android程序员不多呢?这是一个问题,我不好回答,但是我想写一篇文章来描述下Android的学习路线,期望可以帮助更多的Android程序员提升自己。由于我也是从一个菜鸟过来的,所以我会结合我的个人经历以及我对Android学习过程的认识来写这篇文章,这会让这篇文章更加真实,而并非纸上谈兵。

    我的工作经历

    前面说到,我也是从一个Android菜鸟过来的。其实这句话放在任何人的身上都是适用的,即大家都是一步步过来的,因此作为初学者也不必因为技术差而郁闷,同理,高手也不要看不起一些所谓的菜鸟,因为这不公平,技术只有在同等的工作年限上才具有一定的可比性,也许你眼中的菜鸟只是个工作半年的新手,而你已经工作5年,可想而知,这根本不具有可比性,搞不好别人5年后可以达到比你更高的技术高度。

    我有若干个技术QQ群,群里(481798332)的小伙伴对我的工作经历比较感兴趣,刚好在这里我就做下介绍。我是硕士研究生毕业,我已经工作3年零3个月了,职位上从最开始的腾讯初级工程师变成了现在的百度Android资深工程师。最开始我并不是做Android的,先是做了半年的C++,接着做了3个月的Web前端,然后公司内部转岗做Android到至今,纯Android工作年限的话其实是2.5年。但是我认为我的Android工作经验(注:工作年限不等同于工作经验)不止2.5年,我投入大量的业余时间在Android开发上,并且我习惯去思考问题、总结问题并将其融会贯通,因此我的Android技术在短时间内有了很大的提升。

    在Android学习过程中,初学者踩过的坑我也都踩过,我也深深地知道大家在学习过程中最棘手的问题是什么。举个例子,在3年前,我想在SlidingMenu中放入一个ListView,发现二者总是不能很好地一起工作,这肯定是由于滑动冲突的问题,我也知道,但是不知道怎么解决。我就去学校图书馆翻遍了所有的Android书籍,无果。大家肯定都知道原因,为什么我无法从书中查找到问题的答案,因为入门书不讲滑动冲突,所谓的高级编程书也不讲。还有一个问题,我曾经以为view.post(runnable)可以让runnable的run方法在线程中执行,所以我就在run方法里面去做耗时的操作,现在想想我当时是多菜啊,因此我曾经也是菜鸟。

    直到若干年后的某一天,我终于琢磨透了滑动冲突的事,然后我就把解决问题的思想写在了CSDN博客上,但是好像看得人并不多,很多人并不能体会我的用心,后来我博客的访问量越来越大,这才慢慢地得到了一些人的关注。后来有一天我有了写书的契机,我想到了我最开始学习Android时所踩过的坑,想到滑动冲突对我的困扰,为了更好地传播我的技术经验,为了让更多的人少踩一些坑,为了让更多地人成为Android高级工程师,我毅然决定将Android开发中最重要的、最疑难的、最容易困扰大家的、成为高级工程师所必备的知识点和盘托出,这就是《Android开发艺术探索》存在的原因以及意义。书的反响怎么样呢?从目前读者的评价来看,内容基本无差评,我收到了很多读者的肯定以及感谢,这说明很多人能够理解我的用心。

    说了那么多,言归正传,下面说下Android学习路线的话题,本文打算从4个阶段来对Android的学习过程做一个全面的分析,分别为Android初级、中级、高级以及资深工程师,具体请看下面的分析。同理,本篇学习路线仍然只针对Android应用开发,不针对Rom开发和逆向工程等。这里虚拟一位“小明”的角色,在这里小明就是Android初学者的代表。

    初级工程师

    小明之前完全没接触过Android开发,是个应届生,他的待遇是13k,然后小明以校招的身份进入了百度,然后小明需要怎么学习才能成为初级工程师呢?这个时候,小明对编程基础、数据结构、C语言都有一定基础,Java语法什么的也都掌握的比较好,Android才有java语言,无奈的是小明并不会搞Android。

    小明首先需要购买一本Android入门的书籍,为了更快地学习Android,小明业余时间也都用来一边看书一边照着书中的例子敲代码,结果2周时间小明就把这本书学了一遍。看完这本书后,小明对Android的历史、结构、代码规范等都有了一个大概的了解,并且,小明已经可以写出一些简单的Activity了。这个时候在小明眼里,Android开发很简单很好玩,通过在xml中摆放一些按钮文本框什么的就可以做一些界面了。

    小明开始跟着他的技术导师做需求,一些简单的小需求小明自然是不在话下了。突然有一天来了一个需求,该需求要求小明在Activity中为一个button加一个动画效果,小明慌了:“完全没接触过,书上也没有讲,怎么办呢?”小明冷静了下,打开了百度搜索,输入“Android 动画”,打开前几个链接,小明恍然大悟,照着网上的例子把需求给实现了。后来导师告诉他:“学好Android,官方文档是必须看的,既全面又权威”。然后小明如获至宝,花了一年时间把上面的guide和training都看了一遍,并且他还动手抄了几个小例子。

    有一天,小明又需要做一个动画相关的需求,这可难不倒小明,它熟练地打开了www.baidu.com,输入“Android 动画”,突然他楞了一下:”总不能每次写动画都要百度一下吧!“,于是他在CSDN开了一个博客,把动画相关的知识点都写上去,为的是后面再写动画相关的代码就不用百度去搜了,事实如何呢?后面再写动画相关的代码,小明的确不用再去百度搜了,因为通过写一篇动画博客,他把动画相关的细节都已经记住了,这样他就可以不用再去参考任何文档了,后来小明还学会了把一些琐碎的不方便放在博客上的东西写到了印象笔记上面,什么时候忘了10秒钟以内都可以快速找回来,而不是花10分钟去再次搜索一遍。

    这里总结一下,Android入门的时候,需要有一本入门书,好好学习书中的内容,同时花一年时间把Android官方文档中的training和guide看一遍,同时通过写博客和记笔记的方式来做总结,建议让自己的每篇博客都有价值些。通过一年时间的学习,相信每个人都可以达到中级工程师的水平。

    技术要求:
    - 基本知识点
    比如四大组件如何使用、如何创建Service、如何进行布局、简单的自定义View、动画等常见技术
    - 书籍推荐
    《第一行代码 Android》、《疯狂Android》

    中级工程师

    小明经过一年的努力学习终于成为Android中级工程师了,月薪变成了17k。到了中级工程师,已经可以在公司里干很多体力活了,但是一些很重要的任务小明还不能一个人承担起来,这个时候小明需要学习的内容就很多了,如下所示:
    - AIDL:熟悉AIDL,理解其工作原理,懂transact和onTransact的区别;
    - Binder:从Java层大概理解Binder的工作原理,懂Parcel对象的使用;
    - 多进程:熟练掌握多进程的运行机制,懂Messenger、Socket等;
    - 事件分发:弹性滑动、滑动冲突等;
    - 玩转View:View的绘制原理、各种自定义View;
    - 动画系列:熟悉View动画和属性动画的不同点,懂属性动画的工作原理;
    - 懂性能优化、熟悉mat等工具
    - 懂点常见的设计模式

    学习方法

    阅读进阶书籍,阅读Android源码,阅读官方文档并尝试自己写相关的技术文章,需要有一定技术深度和自我思考。在这个阶段的学习过程中,有2个点是比较困扰大家的,一个是阅读源码,另一个是自定义View以及滑动冲突。

    如何阅读源码呢?这是个头疼的问题,但是源码必须要读。阅读源码的时候不要深入代码细节不可自拔,要关注代码的流程并尽量挖掘出对应用层开发有用的结论。另外仔细阅读源码中对一个类或者方法的注释,在看不懂源码时,源码中的注释可以帮你更好地了解源码中的工作原理,这个过程虽然艰苦,但是别无他法。

    如何玩转自定义View呢?我的建议是不要通过学习自定义view而学习自定义view。为什么这么说呢?因为自定义view的种类太多了,各式各样的绚丽的自定义效果,如何学的玩呢!我们要透过现象看本质,更多地去关注自定义view所需的知识点,这里做如下总结:
    - 搞懂view的滑动原理
    - 搞懂如何实现弹性滑动
    - 搞懂view的滑动冲突
    - 搞懂view的measure、layout和draw
    - 然后再学习几个已有的自定义view的例子
    - 最后就可以搞定自定义view了,所谓万变不离其宗

    大概再需要1-2年时间,即可达到高级工程师的技术水平。我个人认为通过《Android开发艺术探索》和《Android群英传》可以缩短这个过程为0.5-1年。注意,达到高级工程师的技术水平不代表就可以立刻成为高级工程师(受机遇、是否跳槽的影响),但是技术达到了,成为高级工程师只是很简单的事。

    技术要求:
    - 稍微深入的知识点
    AIDL、Messenger、Binder、多进程、动画、滑动冲突、自定义View、消息队列等
    - 书籍推荐
    《Android开发艺术探索》、《Android群英传》

    高级工程师

    小明成为了梦寐以求的高级工程师,月薪达到了20k,还拿到了一丢丢股票。这个时候小明的Android水平已经不错了,但是小明的目标是资深工程师,小明听说资深工程师月薪可以达到30k+。

    为了成为Android资深工程师,需要学习的东西就更多了,并且有些并不是那么具体了,如下所示:
    - 继续加深理解”稍微深入的知识点“中所定义的内容
    - 了解系统核心机制:
    1. 了解SystemServer的启动过程
    2. 了解主线程的消息循环模型
    3. 了解AMS和PMS的工作原理
    4. 能够回答问题”一个应用存在多少个Window?“
    5. 了解四大组件的大概工作流程
    6. …
    - 基本知识点的细节
    1. Activity的启动模式以及异常情况下不同Activity的表现
    2. Service的onBind和onReBind的关联
    3. onServiceDisconnected(ComponentName className)和binderDied()的区别
    4. AsyncTask在不同版本上的表现细节
    5. 线程池的细节和参数配置
    6. …
    - 熟悉设计模式,有架构意识

    学习方法

    这个时候已经没有太具体的学习方法了,无非就是看书、看源码和做项目,平时多种总结,尽量将知识融会贯通从而形成一种体系化的感觉。同时这个阶段对架构是有一定要求的,架构是抽象的,但是设计模式是具体的,所以一定要加强下设计模式的学习。关于设计模式的学习,最近一本新书推荐给大家《Android 源码设计模式解析与实战》,既可以学习设计模式,又可能体会到Android源码中的设计思想,我最近也在阅读此书。

    技术要求:
    - 稍微深入的知识点
    - 系统核心机制
    - 基本知识点的细节
    - 设计模式和架构
    - 书籍推荐
    《Android开发艺术探索》、《Android 源码设计模式解析与实战》、《Android内核剖析》

    资深工程师

    这个阶段的程序员也许并没有太具体的学习路线了。

    交流方式

    • QQ交流群:635778578
    • 欢迎关注我的公众号,会持续更新Android干货
      cover
    • 欢迎加入我的知识星球,一起学习交流
      cover
    展开全文
  • 最近有个项目的需求是做个三级筛选菜单,前一级的选择会影响到下一级的结果,花了好一些时间终于做出来,不过感觉还是不是特别好。  先看一下测试的效果图:    好了,说一下我是怎么实现这个效果的。 ...
  • 正好周末外卖点得多,就仿仿“饿了么”好了。先上图吧,这样的订单页面是不是很眼熟:右边的listview分好组以后,在左边的Tab页建立索引。可以直接导航,是不是很方便。关键在于右边滑动,左边也会跟着滑;而点击...
  • 项目Github托管地址:https://github.com/zhouzhuo810/ZzSecondaryLinkage效果图How to use it ?准备工作①第步,添加布局 android:id="@+id/zz_linkage" android:
  • 好了,今天是分享android实现三菜单联动效果,这个demo我也折腾了两三个晚上,到了第三菜单有点复杂,下面带着大家看下代码。项目结构: 为了让大家更有的耐心的阅读, 我先从简单的开始说起,我们先看下...
  • 城市联动,城市列表展示 利用Json解析本地json文件,展示城市数据列表,点击字母联动,模糊查询功能: 1.引入相关包 build.gradle //gson解析 compile 'com.google.code.gson:gson:2.8.0' compile files...
  • 这种横向的二菜单在很多的app都有所应用.效果看起来还是非常的美观的.也算是项目需要,自己也就学了一下这个效果,首先说一下逻辑.实现的方式其实并不是很难..只不过逻辑上可能有点复杂.原理其实就是个按钮.当触发...
  • 、 Service简介Service是android 系统中的四大组件之(Activity、Service、BroadcastReceiver、ContentProvider),它跟Activity的级别差不多,但不能自己运行只能后台运行,并且可以和其他组件进行交互。...
  • 快速实现Android多级树形列表,这个库是在鸿洋多级树形列表demo中修改而来。 解决的问题: 1. 支持ID为int类型和String类型。 2. 支持多级复选框选中,使用只需行代码。 3. 支持动态更新数据并保持原有...
  • 虽然好几个月没更新博客了,但是老罗一直有在准备可以分享的东西的。除了早前在微博分享Android4.2相关技术之外,...可以作为《老罗的Android之旅》博客和《Android系统源代码情景分析》书的导读,希望对大家有帮助。
  • 参考博客: ... http://www.apkbus.com/android-124715-1-1.html 有时候,使用ListView并不能满足应用程序所需要...有些应用程序需要多组ListViw,这时候我们就要使用种新的控件ExpandableListView——可以扩展的List
  • 很多App,都有二菜单出现,但android 本身实现的菜单又比较难看;前些天我自己思想了个,供大家学习,为方便学习,这里我只用最简单的字符串菜单,如果大家想用更复杂或好看的,可以自定义listview 的子项即可。 ...
  • 俩侧列表的adapter ClassAdapter package com.advance.yongliu.linkagedata; import android.graphics.Color; import android.support.annotation.Nullable; import ...
  • 由于本人所作的项目需要用到这种列表式的收缩与展开,因此,就好好研究了有关这方面的一些知识,当然,也借鉴了网上一些成功的案列。下面就是我模拟测试的个展示界面。实现上面的这些功能,我主要是通过...
  • 这里就有个解决办法,就是用事务将两张表关联起来,并且最后生成一张视图。 现有两张表 EmployeesDept 视图 ViewEmps:显示雇员信息和他所在的部门 创建数据库 自定义个辅助类继承SQLiteOpenH
1 2 3 4 5 ... 20
收藏数 26,141
精华内容 10,456
关键字:

一级关联列表android