Android 中动态的向布局中添加控件

原创 2015年11月19日 09:19:58





先看一下效果图:




注: 这里使用的是一个自定义的布局文件,你可以向这个布局文件中添加任何控件,它也会动态的依据控件 的大小,动态的排列控件的分布

注:这里使用到的更新界面的方法:http://blog.csdn.net/zl18603543572/article/details/49915701


java代码中的实现过程:


import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;

public class MainActivity extends Activity {

    private ScrollView mScroller;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_main);
        mScroller = new ScrollView(this);
        /**
         * 这里使用的是自定义的一个布局文件
         */

        final FlowLayout flowLayout = new FlowLayout(this);

        /**
         * 这里设置的值是为方便而这样写出的,这里只演示方法
         */
        //设置四周的padding值
        flowLayout.setPadding(10, 10, 10, 10);
        //设置水平间距
        flowLayout.setHorizontalSpacing(20);
        //设置垂直间距
        flowLayout.setVerticalSpacing(20);


        Button button = new Button(this);

        button.setWidth(getWindowManager().getDefaultDisplay().getWidth());
        button.setText("addView");

        flowLayout.addView(button);
        addChildView(flowLayout);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                /**
                 * 点击按钮 动态的向布局文件中添加一个textview
                 */
                TextView textView = new TextView(MainActivity.this);
                textView.setText("addviewones");
                textView.setTextColor(Color.RED);
                textView.setTextSize(20);
                /**
                 * 添加到布局文件中去
                 */
                flowLayout.addView(textView);
                /**
                 * 更新界面
                 */
                flowLayout.invalidate();

            }
        });
    }

    /**
     * 设置界面的方法
     * @param flowLayout
     */
    public void addChildView(View flowLayout){
        mScroller.addView(flowLayout);
        setContentView(mScroller);


    }

}



自定义的布局文件


import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;

public class FlowLayout extends ViewGroup {
    private final int DEFAULT_SPACING = 10;
    private int horizontalSpacing = DEFAULT_SPACING;//水平间距
    private int verticalSpacing = DEFAULT_SPACING;//行与行之间的垂直间距

    //用来保存所有的行对象
    private ArrayList<Line> lineList = new ArrayList<Line>();
    public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public FlowLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FlowLayout(Context context) {
        super(context);
    }





    /**
     * 在onMeasure中完成分行的操作,就是排座位表;
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        lineList.clear();
        //1.获取FlowLayout的宽度
        int width = MeasureSpec.getSize(widthMeasureSpec);
        //2.计算用于实际比较的宽度,就是width减去左右的padding值
        int noPaddingWidth = width - getPaddingLeft()- getPaddingRight();

        //3.遍历所有的子TextView,进行分行操作
        Line line = new Line();//只要不换行,始终都是同一个Line对象
        for (int i = 0; i<getChildCount(); i++) {
            View childView = getChildAt(i);//获取子TextView
            childView.measure(0,0);//引起view的onMeasure方法回调,从而保证后面的方法能够有值

            //4.如果当前line中 没有TextView,则直接放入当前Line中
            if(line.getViewList().size()==0){
                line.addLineView(childView);
            }else if(line.getWidth()+horizontalSpacing+childView.getMeasuredWidth()>noPaddingWidth) {
                //5.如果当前line的宽+水平间距+childView的宽大于noPaddingWidth,则换行
                lineList.add(line);//先保存之前的line对象

                line = new Line();//重新创建Line
                line.addLineView(childView);//将chidlView放入新的Line
            }else {
                //6.如果小于noPaddingWidth,则将childView放入当前Line中
                line.addLineView(childView);
            }

            //7.如果当前childView是最后一个,那么就会造成最后的一个Line对象丢失,
            if(i==(getChildCount()-1)){
                lineList.add(line);//保存最后的line对象
            }
        }

        //for循环结束后,lineList就存放了所有的Line对象,而每个line中有记录自己的所有TextView
        //为了能够垂直的摆放所有的Line的TextView,所以要给当前FlowLayout设置对应的宽高,
        //计算所需要的高度:上下的padding + 所有line的高度   + 所有line之间的垂直间距
        int height = getPaddingTop()+getPaddingBottom();
        for (int i = 0; i < lineList.size(); i++) {
            height += lineList.get(i).getHeight();
        }
        height += (lineList.size()-1)*verticalSpacing;

        setMeasuredDimension(width,height);//向父View申请对应的宽高
    }

    /**
     * 摆放操作,让所有的子TextView摆放到指定的位置上面
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int paddingLeft = getPaddingLeft();
        int paddingTop = getPaddingTop();
        for (int i = 0; i < lineList.size(); i++) {
            Line line = lineList.get(i);//获取line对象

            //从第二行开始,他们的top总是比上一行多一个行高+垂直间距
            if(i>0){
                paddingTop += lineList.get(i-1).getHeight()+verticalSpacing;
            }
            ArrayList<View> viewList = line.getViewList();//获取line所有的TextView
            //1.计算出当前line的留白区域的值
            int remainSpacing = getLineRemainSpacing(line);
            //2.计算每个TextView分到多少留白
            float perSpacing = remainSpacing/viewList.size();

            for (int j = 0; j < viewList.size(); j++) {
                View childView = viewList.get(j);//获取每个TextView
                //3.将perSpacing增加到每个TextView的宽度上
                int widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) (childView.getMeasuredWidth()+perSpacing),MeasureSpec.EXACTLY);
                childView.measure(widthMeasureSpec,0);

                if(j==0){
                    //摆放每行的第一个TextView
                    childView.layout(paddingLeft,paddingTop,paddingLeft+childView.getMeasuredWidth()
                            ,paddingTop+childView.getMeasuredHeight());
                }else {
                    //摆放后面的TextView,需要参照前一个View
                    View preView = viewList.get(j-1);
                    int left = preView.getRight()+horizontalSpacing;
                    childView.layout(left,preView.getTop(),left+childView.getMeasuredWidth(),
                            preView.getBottom());
                }
            }
        }
    }

    /**
     * 获取line的留白区域
     * @param line
     * @return
     */
    private int getLineRemainSpacing(Line line){
        return getMeasuredWidth()-getPaddingLeft()-getPaddingRight()-line.getWidth();
    }

    /**
     * 定义行对象,用来封装每行的所有TextView,以及宽和高
     * @author Administrator
     *
     */
    class Line{
    //用来记录当前行的所有TextView
        private ArrayList<View> viewList = new ArrayList<View>();
        //表示当前行所有TextView的宽,还有他们之间的水平间距
        private int width;
        //当前行的高度
        private int height;

        /**
         * 添加一个TextView到viewList中
         * @param lineView
         */
        public void addLineView(View lineView){
            if(!viewList.contains(lineView)){
                viewList.add(lineView);

                //更新width
                if(viewList.size()==1){
                    //如果是第一个TextView,那么width就是lineView的宽度
                    width = lineView.getMeasuredWidth();
                }else {
                    //如果不是第一个,则要在当前width的基础上+水平间距+lineView的宽度
                    width += horizontalSpacing + lineView.getMeasuredWidth();
                }
                //更新height,在此所有的TextView的高度都是一样的
                height = Math.max(height,lineView.getMeasuredHeight());
            }
        }

        /**
         * 获取当前Line中的所有TextView
         * @return
         */
        public ArrayList<View> getViewList() {
            return viewList;
        }
        /**
         * 获取当前Line的宽度
         * @return
         */
        public int getWidth() {
            return width;
        }
        /**
         * 获取当前Line的高度
         * @return
         */
        public int getHeight() {
            return height;
        }

    }






    /**
     * 设置行与行之间的垂直间距
     * @param
     */
    public void setVerticalSpacing(int verticalSpacing){
        if(verticalSpacing>0){
            this.verticalSpacing = verticalSpacing;
        }
    }
    /**
     * 设置子View直接的水平间距
     * @param horizontalSpacing
     */
    public void setHorizontalSpacing(int horizontalSpacing){
        if(horizontalSpacing>0){
            this.horizontalSpacing = horizontalSpacing;
        }
    }




}



注:在使用的时候 ,可以直接复制本代码到项目中即可



版权声明:本文为博主原创文章,未经博主允许不得转载。

在已有布局中动态添加控件

转自: http://blog.csdn.net/andypan1314/article/details/7306395
  • tdstds
  • tdstds
  • 2014年06月10日 18:25
  • 3185

Android中利用LinearLayout动态添加控件

在androidUI布局中,一般都是利用xml来布局控件,这是比较方便和直观的,但是有时却需要动态生成,下面就举2个简单例子来说明怎么动态添加控件: 1.动态添加2个垂直排列的Button @Over...
  • zcpangzi
  • zcpangzi
  • 2010年03月26日 20:19
  • 131351

js动态创建控件

最近的工作中需要在弹出窗口中选择子项并返回到父窗口中,且在父窗口中要求根据返回值自动创建控件,一下是示例代码。父窗口中的html代码: 我现在居住的城市:  ...
  • huhqian
  • huhqian
  • 2010年04月08日 20:17
  • 9081

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

动态添加综合布局---动态添加控件及将某XML动态加入到Activity显示(续)

前言:

android:动态创建多个按钮 并给每个按键添加监听事件

//获取屏幕大小,以合理设定 按钮 大小及位置   DisplayMetrics dm = new DisplayMetrics();   getWindowManager().getDefaul...

Android给布局、控件加阴影效果

增加阴影效果,让控件或者布局看起来有立体的效果,总的来说有两种解决方案。1,直接使用属性: android:elevation="4dp"这样一句代码,就实现了效果,elevation表示海拔,就是布...

Android使用addView动态添加组件

在项目开发中,我们经常需要进行动态添加组件,其中可添加的部分有两项:布局和组件  其中,添加的布局主要有RelativeLayout型(相对布局)的和LinearLayout(线性布局)       ...
  • suwu150
  • suwu150
  • 2016年05月08日 22:51
  • 8751

Android 动态生成多个控件并实现点击

我们来看下动态效果图,如下: 首先这个按钮是根据所填的数动态生成的,然后还要设置他的点击事件。这个demo需要两个layout和一个activity: 首先来看下这两个布局文件: 1.这个是界面的...
  • AA_chao
  • AA_chao
  • 2016年11月16日 17:40
  • 1213

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android 中动态的向布局中添加控件
举报原因:
原因补充:

(最多只允许输入30个字)