Android UI设计和形成原理(实现三级菜单)

来源:互联网 发布:小袄淘宝网,金丝绒的 编辑:程序博客网 时间:2024/05/22 17:23

本次要实现的是动态编码之三级菜单的实现,在实际应用开发中经常会使用到三级菜单,比如商城项目中的省市区,分类等等。

问题:界面加载是一次性new 大量的控件还是先加载一级菜单,点击一级菜单加载他对应的二级菜单

答:这个很明显是后者更符合开发思维,因为客户不可能每个级别都一一点开,能点开所有级别的只有万恶的测试人员。

界面加载方案:

1.数据进行一次性加载(一次把服务端传递过来的数据解析封装到数据模型

2.先加载一级菜单,点击一级菜单加载他对应的二级菜单


技术要点:动态编写界面,递归算法,javaBean;


实现过程

1.建立javabean封装数据

package com.xiaoyao.android.mytree;import java.util.ArrayList;import java.util.List;/** * Created by Administrator on 2016/6/18. */public class Node {    private int id;//当前节点的自身的ID;    private int pId = 0;//根节点pId    private String name;//菜单的名字    private int level;//当前的级别    private boolean isExpand = false;//是否只展开一个子菜单    private Node parent;//父亲节点    private List<Node> children=new ArrayList<>();    public Node() {        super();    }    public Node(int id,int pId,String name){        super();        this.id=id;        this.pId=pId;        this.name=name;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public int getpId() {        return pId;    }    public void setpId(int pId) {        this.pId = pId;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getLevel() {        return parent==null?0:parent.getLevel()+1;    }    public void setLevel(int level) {        this.level = level;    }    public boolean isExpand() {        return isExpand;    }    public void setExpand(boolean expand) {        isExpand = expand;        if (!isExpand){            for (Node node:children){                node.setExpand(isExpand);            }        }    }    public Node getParent() {        return parent;    }    public void setParent(Node parent) {        this.parent = parent;    }    public List<Node> getChildren() {        return children;    }    public void setChildren(List<Node> children) {        this.children = children;    }    /**     * 是否为根节点     */    public boolean isRoot(){        return parent==null;    }    /**     * 判断父节点是否展开     */    public boolean isParentExpand(){        if (parent==null){            return false;        }        return parent.isExpand();    }    /**     * 是否为叶子节点     */    public boolean isLeaf(){        return children.size()==0;    }}
以上要特别说明的是getLevel()方法在该方法中返回值是当前的级别,在此通过了递归的算法得到当前级别的父级别然后+1从而得到当前的级别

return parent == null ? 0 :parent.getLevel() + 1 ;


2.创建三级列表视图

package com.xiaoyao.android.mytree;import android.content.Context;import android.graphics.Color;import android.text.Layout;import android.view.View;import android.widget.LinearLayout;import android.widget.ScrollView;import android.widget.TextView;import android.widget.Toast;import java.util.ArrayList;import java.util.List;/** * Created by Administrator on 2016/6/18. */public class MyTree extends LinearLayout {    List<Node> mDatas;//数据源    private Context mContext;//上下文    /**     * 以下为容器参数     */    LayoutParams rootLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);    LayoutParams itemLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);    LayoutParams dividerLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, 1);    public MyTree(Context context) {        super(context);        this.mContext=context;    }    public void setData(List<Node> mDatas) {        this.mDatas = mDatas;        initView();    }    /**     * 初始化界面     */    private void initView(){        //添加一个滚动视图        ScrollView scrollView=new ScrollView(mContext);        scrollView.setLayoutParams(rootLayoutParams);        scrollView.setBackgroundColor(Color.parseColor("#f0f0f0"));        //添加一个线性布局作为一级菜单的容器        LinearLayout rootLayout=new LinearLayout(mContext);        rootLayout.setLayoutParams(rootLayoutParams);        rootLayout.setOrientation(LinearLayout.VERTICAL);                //加载一级菜单        //得到数据源中所有的一级菜单        List<Node> rootNodes=getListByPid(0);        for (int i=0;i<rootNodes.size();i++){            Node rootNode=rootNodes.get(i);            //初始化一级布局,在这里只是简单的使用TextView作为布局            TextView firstLevelView=new TextView(mContext);            firstLevelView.setLayoutParams(itemLayoutParams);            //添加ID            firstLevelView.setId(rootNode.getId());            //设置名字            firstLevelView.setText(rootNode.getName());            firstLevelView.setTextColor(Color.WHITE);            firstLevelView.setBackgroundColor(Color.BLUE);            firstLevelView.setPadding(30,30,30,30);            //添加一级菜单到一级菜单的容器中            rootLayout.addView(firstLevelView);            //添加分割线,没添加一个一级菜单添加一条横线            rootLayout.addView(getDivider());            //准备加载对应的子菜单(2级菜单容器)            LinearLayout secondLayout=new LinearLayout(mContext);            secondLayout.setLayoutParams(itemLayoutParams);            secondLayout.setOrientation(LinearLayout.VERTICAL);            //在未点击时设置2级菜单容器隐藏不可见            secondLayout.setVisibility(GONE);            //让一级菜单和他自己对应的2级菜单有关联,做标记            firstLevelView.setTag(secondLayout);            //将2级菜单的容器添加到父一级菜单容器中            rootLayout.addView(secondLayout);            //添加完善一级菜单的点击事件            firstLevelView.setOnClickListener(new OnClickListener() {                @Override                public void onClick(View v) {                    //得到二级菜单的布局容器                    LinearLayout parentLayout= (LinearLayout) v.getTag();                    if (parentLayout.getChildCount()==0){                        //表示没有添加过                        addMenuChild(parentLayout,v.getId());                    }else if (parentLayout.isShown()){                        parentLayout.setVisibility(View.GONE);                    }else{                        parentLayout.setVisibility(View.VISIBLE);                    }                }            });        }        scrollView.addView(rootLayout);        addView(scrollView);    }    private void addMenuChild(LinearLayout parentLayout, int id) {        //设置容器显示        parentLayout.setVisibility(VISIBLE);        //得到该级别下的猜的的数据源        List<Node>childNodes=getListByPid(id);        if (childNodes.size()>0){            for (int i=0;i<childNodes.size();i++){                Node childNode=childNodes.get(i);                //创建2级菜单                TextView secondLevelView=new TextView(mContext);                secondLevelView.setId(childNode.getId());                secondLevelView.setLayoutParams(itemLayoutParams);                secondLevelView.setText(childNode.getName());                secondLevelView.setTextColor(Color.BLACK);                List<Node> grandChildNode=getListByPid(childNode.getpId());                if (grandChildNode.size() > 0){                    secondLevelView.setPadding(60, 30, 30, 30);                    secondLevelView.setTextColor(Color.GRAY);                    secondLevelView.setBackgroundColor(Color.parseColor("#f0f0f0"));                }else{                    secondLevelView.setPadding(120, 30, 30, 30);                    secondLevelView.setTextColor(Color.BLACK);                    secondLevelView.setBackgroundColor(Color.WHITE);                }                //2级容器将2级菜单的item保存起来                parentLayout.addView(secondLevelView);                parentLayout.addView(getDivider());                //准备下一级子菜单                LinearLayout thirdLayout=new LinearLayout(mContext);                thirdLayout.setLayoutParams(itemLayoutParams);                thirdLayout.setOrientation(LinearLayout.VERTICAL);                thirdLayout.setVisibility(View.GONE);                secondLevelView.setTag(thirdLayout);                parentLayout.addView(thirdLayout);                //完善子菜单的点击事件                secondLevelView.setOnClickListener(new OnClickListener() {                    @Override                    public void onClick(View v) {                        //得到三级菜单的布局容器                        LinearLayout parentLayout= (LinearLayout) v.getTag();                        if (parentLayout.getChildCount()==0){                            //表示没有加载过                            addMenuChild(parentLayout,v.getId());                        }else if (parentLayout.isShown()){                            parentLayout.setVisibility(GONE);                        }else {                            parentLayout.setVisibility(VISIBLE);                        }                    }                });            }        }else {            Toast.makeText(mContext, "没有数据,别点了!",Toast.LENGTH_SHORT).show();        }    }    /**     * 根据pid得到对象的菜单集合     * @param pid     * @return     */    private List<Node> getListByPid(int pid) {        List<Node> resultNodes=new ArrayList<>();        for (int i=0;i<mDatas.size();i++){            Node node=mDatas.get(i);            if (node.getpId()==pid){                resultNodes.add(node);            }        }        return resultNodes;    }    /**     * 添加横线视图     * @return     */    public View getDivider() {        View divider=new View(mContext);        divider.setLayoutParams(dividerLayoutParams);        divider.setBackgroundColor(Color.GRAY);        return divider;    }}

3.创建数据源并且展示三级菜单

package com.xiaoyao.android.mytree;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import java.util.ArrayList;import java.util.List;/** * 动态编码实现我的三级菜单 */public class MainActivity extends AppCompatActivity {    public List<Node>mDatas=new ArrayList<>();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        initDatas();        //动态创建我们的三级菜单,递归算法        MyTree myTree=new MyTree(this);        myTree.setData(mDatas);        setContentView(myTree);    }    //准备好数据源(开发获取Json  xml数据源解析)    private void initDatas() {        // id , pid , label , 其他属性        mDatas.add(new Node(1, 0, "游戏"));        mDatas.add(new Node(2, 0, "文档"));        mDatas.add(new Node(3, 0, "程序"));        mDatas.add(new Node(4, 0, "视频"));        mDatas.add(new Node(5, 0, "音乐"));        mDatas.add(new Node(6, 0, "照片"));        mDatas.add(new Node(7, 0, "学习"));        mDatas.add(new Node(8, 0, "娱乐"));        mDatas.add(new Node(9, 0, "美食"));        mDatas.add(new Node(10, 0, "备忘录"));        mDatas.add(new Node(11, 1, "DOTA"));        mDatas.add(new Node(12, 1, "LOL"));        mDatas.add(new Node(13, 1, "war3"));        mDatas.add(new Node(14, 11, "剑圣"));        mDatas.add(new Node(15, 11, "敌法"));        mDatas.add(new Node(16, 11, "影魔"));        mDatas.add(new Node(17, 12, "德玛西亚"));        mDatas.add(new Node(18, 12, "潘森"));        mDatas.add(new Node(19, 12, "蛮族之王"));        mDatas.add(new Node(20, 13, "人族"));        mDatas.add(new Node(21, 13, "兽族"));        mDatas.add(new Node(22, 13, "不死族"));        mDatas.add(new Node(23, 2, "需求文档"));        mDatas.add(new Node(24, 2, "原型设计"));        mDatas.add(new Node(25, 2, "详细设计文档"));        mDatas.add(new Node(26, 23, "需求调研"));        mDatas.add(new Node(27, 23, "需求规格说明书"));        mDatas.add(new Node(28, 23, "需求报告"));        mDatas.add(new Node(29, 24, "QQ原型"));        mDatas.add(new Node(30, 24, "微信原型"));        mDatas.add(new Node(31, 25, "刀塔传奇详细设计"));        mDatas.add(new Node(32, 25, "羽禾直播设计"));        mDatas.add(new Node(33, 25, "YNedut设计"));        mDatas.add(new Node(34, 25, "微信详细设计"));        mDatas.add(new Node(35, 3, "面向对象"));        mDatas.add(new Node(36, 3, "非面向对象"));        mDatas.add(new Node(37, 35, "C++"));        mDatas.add(new Node(38, 35, "JAVA"));        mDatas.add(new Node(39, 36, "Javascript"));        mDatas.add(new Node(40, 36, "C"));        mDatas.add(new Node(41, 4, "电视剧"));        mDatas.add(new Node(42, 4, "电影"));        mDatas.add(new Node(43, 4, "综艺"));        mDatas.add(new Node(44, 4, "动画"));        mDatas.add(new Node(45, 41, "花千骨"));        mDatas.add(new Node(46, 41, "三国演义"));        mDatas.add(new Node(47, 41, "匆匆那年"));        mDatas.add(new Node(48, 41, "亮剑"));        mDatas.add(new Node(49, 42, "金刚狼"));        mDatas.add(new Node(50, 42, "复仇者联盟"));        mDatas.add(new Node(51, 42, "碟中谍"));        mDatas.add(new Node(52, 42, "谍影重重"));        mDatas.add(new Node(53, 43, "极限挑战"));        mDatas.add(new Node(54, 43, "奔跑吧兄弟"));        mDatas.add(new Node(55, 43, "我去上学啦"));        mDatas.add(new Node(56, 43, "中国好声音"));        mDatas.add(new Node(57, 44, "火影忍者"));        mDatas.add(new Node(58, 44, "海贼王"));        mDatas.add(new Node(59, 44, "哆啦A梦"));        mDatas.add(new Node(60, 44, "蜡笔小新"));    }}

以上案例只是做了一个动态布局的一个简单的入门,上面案例的三级菜单有许多可扩展之处,比如能否像expandListView设置开关控制是否只展开一个子菜单之处能,其实是可以,我在javabean已经为刚才的问题做了伏笔。

0 0
原创粉丝点击