zoukankan      html  css  js  c++  java
  • 自定义View(四) ViewGroup 动态添加变长Tag标签 支持自动换行

        欲实现如下效果

        

        思路很简单就2步:

        1、测量出ViewGroup的大小

        2、找出子View的位置

    若要实现动态添加标签view,就要实现ViewGroup的onMeasure()、onLayout()方法,这两个方法可由该ViewGroup的requestLayout()方法触发,

    onMeasure是对ViewGroup的大小计算,onLayout是针对View(可以是子View也可以是本View)的位置设置

     

    关于这几个方法的流程图如下:

        

            

    /**
     * 流式标签(动态的,根据传入的数据动态添加标签)
     */
    public class CustomerFlowLayout extends ViewGroup {
        
        private List<String> mTags = new ArrayList<String>();
        
        public CustomerFlowLayout(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
     
        public CustomerFlowLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
     
        public CustomerFlowLayout(Context context) {
            super(context);
        }
        
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
            
            //当前ViewGroup的总高度
            int totalHeight= 0;
            //所有行中的最大宽度
            int maxLineWidth = 0;
            
            //当前行的最大高度
            int lineMaxHeight = 0;
            //当前行的总宽度
            int currentLineWidth = 0;
            
            //每个childView所占用的宽度
            int childViewWidthSpace = 0;
            //每个childView所占用的高度
            int childViewHeightSpace = 0;
            
            int count = getChildCount();
            MarginLayoutParams layoutParams;
            
            for(int i = 0; i < count; i++){
                View child = getChildAt(i);
                
                if(child.getVisibility() != View.GONE){//只有当这个View能够显示的时候才去测量
                    //测量每个子View,以获取子View的宽和高
                    measureChild(child, widthMeasureSpec, heightMeasureSpec);
                    
                    layoutParams = (MarginLayoutParams) child.getLayoutParams();
                    
                    childViewWidthSpace = child.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;
                    childViewHeightSpace = child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;
                    
                    if(currentLineWidth + childViewWidthSpace > widthSize){//表示如果当前行再加上现在这个子View,就会超出总的规定宽度,需要另起一行
                        totalHeight += lineMaxHeight;
                        if(maxLineWidth < currentLineWidth){//如果行的最长宽度发生了变化,更新保存的最长宽度
                            maxLineWidth = currentLineWidth;
                        }
                        currentLineWidth = childViewWidthSpace;//另起一行后,需要重置当前行宽
                        lineMaxHeight = childViewHeightSpace;
                    }else{//表示当前行可以继续添加子元素
                        currentLineWidth += childViewWidthSpace;
                        if(lineMaxHeight < childViewHeightSpace){
                            lineMaxHeight = childViewHeightSpace;
                        }
                    }
                }
            }
            
            setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : maxLineWidth, heightMode == MeasureSpec.EXACTLY ? heightSize : totalHeight);
            
        }
     
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            //当前是第几行
            int currentLine = 1;
            //存放每一行的最大高度
            List<Integer> lineMaxHeightList = new ArrayList<Integer>();
            
            //每个childView所占用的宽度
            int childViewWidthSpace = 0;
            //每个childView所占用的高度
            int childViewHeightSpace = 0;
            
            //当前行的最大高度
            int lineMaxHeight = 0;
            //当前行的总宽度
            int currentLineWidth = 0;
            
            int count = getChildCount();
            MarginLayoutParams layoutParams;
            
            for(int i = 0; i < count; i++){
                int cl= 0, ct = 0, cr = 0, cb = 0;
                View child = getChildAt(i);
                if(child.getVisibility() != View.GONE){//只有当这个View能够显示的时候才去测量
                
                    layoutParams = (MarginLayoutParams) child.getLayoutParams();
                    childViewWidthSpace = child.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;
                    childViewHeightSpace = child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;
                    
                    System.out.println("getWidth()---->"+getWidth());
                    
                    if(currentLineWidth + childViewWidthSpace > getWidth()){//表示如果当前行再加上现在这个子View,就会超出总的规定宽度,需要另起一行
                        lineMaxHeightList.add(lineMaxHeight);//此时先将这一行的最大高度加入到集合中
                        //新的一行,重置一些参数
                        currentLine++;
                        currentLineWidth = childViewWidthSpace;
                        lineMaxHeight = childViewHeightSpace;
                        
                        cl = layoutParams.leftMargin;
                        if(currentLine > 1){
                            for(int j = 0; j < currentLine - 1; j++){
                                ct += lineMaxHeightList.get(j);
                            }
                            ct += layoutParams.topMargin ;
                        }else{
                            ct = layoutParams.topMargin;
                        }
                    }else{//表示当前行可以继续添加子元素
                        cl = currentLineWidth + layoutParams.leftMargin;
                        if(currentLine > 1){
                            for(int j = 0; j < currentLine - 1; j++){
                                ct += lineMaxHeightList.get(j);
                            }
                            ct += layoutParams.topMargin;
                        }else{
                            ct = layoutParams.topMargin;
                        }
                        currentLineWidth += childViewWidthSpace;
                        if(lineMaxHeight < childViewHeightSpace){
                            lineMaxHeight = childViewHeightSpace;
                        }
                    }
                    
                    cr = cl + child.getMeasuredWidth();
                    cb = ct + child.getMeasuredHeight();
                    
                    child.layout(cl, ct, cr, cb);
                
                }
            }
        }
        
        @Override
        public LayoutParams generateLayoutParams(AttributeSet attrs) {
            return new MarginLayoutParams(getContext(), attrs);
        }
        
        public void setTags(List<String> tags){
            if(tags!= null){
                mTags.clear();
                mTags.addAll(tags);
                for(int i = 0; i < mTags.size(); i++){
                    TextView tv = new TextView(getContext());
                    MarginLayoutParams lp = new MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT, MarginLayoutParams.WRAP_CONTENT);
                    lp.setMargins(15, 15, 15, 15);
    //                lp.width = MarginLayoutParams.WRAP_CONTENT;
    //                lp.height = MarginLayoutParams.WRAP_CONTENT;
                    tv.setLayoutParams(lp);
                    tv.setBackgroundResource(R.drawable.tv_bg);
                    /*
                     * setPadding一定要在setBackgroundResource后面使用才有效!!!
                     * http://stackoverflow.com/questions/18327498/setting-padding-for-textview-not-working
                     */
                    tv.setPadding(15, 15, 15, 15);
                    tv.setTextColor(Color.WHITE);
                    
                    tv.setText(mTags.get(i));
                    
                    tv.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            if(listener != null){
                                listener.onClick(v);
                            }
                        }
                    });
                    
                    addView(tv);
                }
                requestLayout();
            }
        }
        
        private OnTagItemClickListener listener;
        public interface OnTagItemClickListener{
            public void onClick(View v);
        }
        public void setOnTagItemClickListener(OnTagItemClickListener l){
            listener = l;
        }
     
    }

              针对在Activity中的使用:

    public class MainActivity extends Activity {
        
        private CustomerFlowLayout customerFlowLayout;
        
        List<String> tags = new ArrayList<String>();
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_dynamic_tagflowlayout);
            
            CustomerFlowLayout = (CustomerFlowLayout) findViewById(R.id.dynamic_tag);
            customerFlowLayout.setOnTagItemClickListener(new OnTagItemClickListener() {
                @Override
                public void onClick(View v) {
                    TextView tv = (TextView) v;
                    Toast.makeText(MainActivity.this, tv.getText().toString(), Toast.LENGTH_SHORT).show();
                }
            });
            
            initData();
            customerFlowLayout.setTags(tags);
        }
     
        private void initData() {
            tags.add("阳哥你好!");
            tags.add("Android开发");
            tags.add("新闻热点");
            tags.add("热水进宿舍啦!");
            tags.add("I love you");
            tags.add("成都妹子");
            tags.add("新余妹子");
            tags.add("仙女湖");
            tags.add("创新工厂");
            tags.add("孵化园");
            tags.add("神州100发射");
            tags.add("有毒疫苗");
            tags.add("顶你阳哥阳哥");
            tags.add("Hello World");
            tags.add("闲逛的蚂蚁");
            tags.add("闲逛的蚂蚁");
            tags.add("闲逛的蚂蚁");
            tags.add("闲逛的蚂蚁");
            tags.add("闲逛的蚂蚁");
            tags.add("闲逛的蚂蚁");
        }
     
    }

       上述的ViewGroup中可以添加 对标签的处理(例如:点击、选中)

      参考资料:

        https://blog.csdn.net/shakespeare001/article/details/51089128

        https://www.cnblogs.com/ldq2016/p/9035332.html

       

  • 相关阅读:
    java并发编程(1)并发程序的取消于关闭
    Matlab插值函数
    log4j的配置
    spring-mvc注解(mvc:annotation-driver,JSON,配置详解)
    matlab画图函数plot()/set/legend
    matlab 曲线拟合
    Linux安装库文件(环境变量和makefile)
    css生成彩色阴影
    JSON.stringify()还可以这么用
    ES6中新增的数组知识记录
  • 原文地址:https://www.cnblogs.com/bimingcong/p/9947739.html
Copyright © 2011-2022 走看看