ACRA 和自定义布局

ACRA : Application crash report for android

  1. 作用: 为自己的应用找bug
  2. 使用步骤:参考文档

自定义布局的实现:流程图

参照流程图:当有孩子时,是否需要对孩子控件大小进行布置,如果需要就得重写onMeasure()这个方法调用child.layout()方法。需要孩子控件布局进行控制也要重写onLayout()方法,需要对控件的显示进行控制时要重写onDraw()方法。

一般实现全部构造函数。

重写

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
    //临时top
    int topmt=0;
    int parentWidth = getMeasuredWidth();

    //获得孩子个数
    int count =getChildCount();
    for(int i=0;i<count;i++){

        //获得孩子实例
        View child=getChildAt(i);
        //获得孩子的高度、宽度
        int childHidth=child.getMeasuredHeight();
        int childWidth=child.getMeasuredWidth();


        if(i%2==0){ //双行

                int left=parentWidth-childWidth;
                int top=topmt;
                int right=left+childWidth;
                int bottom=top+childHidth;
                child.layout(left, top, right, bottom);

        }else{//单行

                int left=0;
                int top=topmt;
                int right=left+childWidth;
                int bottom=top+childHidth;
                child.layout(left, top, right, bottom);

        }
        topmt+=childHidth;
    }
}

还需要重写onMeasure()

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
    //获得父亲的宽高
    int widthsize=MeasureSpec.getSize(widthMeasureSpec);
    int heightsize=MeasureSpec.getSize(heightMeasureSpec);

    measureChildren(0, 0);//设置孩子,为0由父亲安排宽高

    setMeasuredDimension(widthsize, heightsize);
}

自定义布局的使用:

<com.cca.definelayout.CustomerLayout 
      xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:id="@+id/customer_layout"
    android:layout_height="match_parent"
    tools:context="com.cca.definelayout.MainActivity" >

    <View 
           android:layout_width="220dp"
            android:layout_height="40dp"
            android:background="#ff0000"
    />

     <View 
           android:layout_width="220dp"
            android:layout_height="40dp"
            android:background="#00ff00"
    />

     <View 
           android:layout_width="220dp"
            android:layout_height="40dp"
            android:background="#fe3300"
    />

    <View 
           android:layout_width="220dp"
            android:layout_height="40dp"
            android:background="#ff0220"
    />

      <View 
           android:layout_width="220dp"
            android:layout_height="40dp"
            android:background="#ffdd00"
    />
</com.cca.definelayout.CustomerLayout>

如果需要切换布局,一般定义一个boolean类型值进行切换

FlowLayout

  1. 分析:
    1. 多行摆放
    2. 单行如果摆不下去,换行摆放

看下效果图:

一下子看到这种布局说真的我无从下手,不知道这个怎么实现,每行个数不一样,列数不一样,后来知道自定义布局可以实现。根据上面的view实现的流程图可以知道,需要对控件的布局、大小进行控制,所以需要重写onLayout()、onMeasure()的方法。再重写方法之前,需要先分析每一行是怎么布局的,以面向对象的思想封装每一行需要的属性、和方法。如下:

行的类

    class Line{
        //存储孩子
        private List<View> mChildViews=new LinkedList<View>();

        private int usedWidth;//已经使用过的宽度
        private int lineHeight;//行最大的高度

        private int maxWidth;//行最大的宽度,父类给的
        private int horizontalSpace;//中间的间隔

        public Line(int maxWidth,int horizontalSpace){
            this.maxWidth=maxWidth;
            this.horizontalSpace=horizontalSpace;
        }
    //判断该行是否能添加view
        public boolean canAddView(View view){
            //如果使用的宽度+准备加的View的宽度+中间的间隔>最大的宽度,加不上去

            //准备加的View的宽度
            int childwidth=view.getMeasuredWidth();

            int size=mChildViews.size();
            if(size==0){
                return true;
            }else if(usedWidth+childwidth+horizontalSpace>maxWidth){
                return false;
            }
            return true;
        }
    //添加view到布局
        public void addView(View view){
            //
            int childWidth=view.getMeasuredWidth();
            int childHeight=view.getMeasuredHeight();
            int size=mChildViews.size();

            if(size==0){
                //没有孩子      已经使用的宽度
                if(childWidth>maxWidth){
                    usedWidth=maxWidth;
                }else{
                    usedWidth=childWidth;
                }
                //高度
                lineHeight=childHeight;

            }else{
                //已经使用的宽度
                usedWidth=usedWidth+childWidth+horizontalSpace;

                //高度
                lineHeight=lineHeight>childHeight?lineHeight:childHeight;
            }
            //加孩子
            mChildViews.add(view);
        }

//给行布局

        public void layout(int left,int top)
        {
            //给孩子布局
            int size=mChildViews.size();

            int tmpLeft=0;

            //将每一行右侧无法显示的空白部分平分给每一行显示的每个控件
            int extraWidth=(int) ((maxWidth-usedWidth)*1f/size+0.5f);

            for(int i=0;i<size;i++){
                View child=mChildViews.get(i);

                int childWidth=child.getMeasuredWidth();
                int childHeight=child.getMeasuredHeight();

                if(extraWidth>0){
                    //希望孩子再宽点,填充右侧空白
                    int widthMeasureSpec=MeasureSpec.makeMeasureSpec(childWidth+extraWidth, MeasureSpec.EXACTLY);
                    int heightMeasureSpec=MeasureSpec.makeMeasureSpec(childHeight,MeasureSpec.EXACTLY);
                    child.measure(widthMeasureSpec, heightMeasureSpec);

                    //重新获得宽高
                     childWidth=child.getMeasuredWidth();
                     childHeight=child.getMeasuredHeight();
                }

                int extraHeight=(int) ((lineHeight-childHeight)/2f+0.5f);

                int l=left+tmpLeft;
                int t=top+extraHeight;
                int r=l+childWidth;
                int b=t+childHeight;
                child.layout(l, t, r, b);

                //添加记录
                tmpLeft +=childWidth + horizontalSpace;
            }

        }
}

重写onLayout()方法:

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
    int left=getPaddingLeft();
    int top=getPaddingTop();

    //让行进行布局
    for(int i=0;i<mLines.size();i++){
        Line line=mLines.get(i);
        //给行布局
        line.layout(left,top);

        //添加top的记录
        top +=line.lineHeight;
        if(i!=mLines.size()-1){
            top +=mVertivalSpace;
        }

    }

}

重写onMeasure()方法

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
    //孩子个数记录清空
    mLines.clear();
    mCurrentLine=null;

    int widthSize=MeasureSpec.getSize(widthMeasureSpec);
    int lineMaxWidth=widthSize-getPaddingLeft()-getPaddingRight();

    //测量孩子完成时,就记录到行里面
    int count=getChildCount();
    for(int i=0;i<count;i++){
        View child=getChildAt(i);

        //孩子不可见时
        if(child.getVisibility()==View.GONE){
            continue;
        }

        //给孩子宽高赋值,父亲给的最大宽高
        measureChild(child, widthMeasureSpec, heightMeasureSpec);

        //将孩子添加到行中
        if(mCurrentLine==null){
            //新建行
            mCurrentLine=new Line(lineMaxWidth,mHorizontalSpace);
            //添加到布局中
            mLines.add(mCurrentLine);
        }
        //给行添加孩子
        if(mCurrentLine.canAddView(child)){
            //可以添加孩子
            mCurrentLine.addView(child);
        }else{
            //加不了
            //换行
            mCurrentLine=new Line(lineMaxWidth,mHorizontalSpace);
            //添加到布局中
            mLines.add(mCurrentLine);
            //再加孩子
            mCurrentLine.addView(child);
        }
    }
    //设置自己的宽高
    int measuredWidth=widthSize;
    int measuredHeight=getPaddingTop()+getPaddingBottom();
    //通过line的高来计算自己的高度
    for(int i=0;i<mLines.size();i++){
        Line line=mLines.get(i);
        measuredHeight +=line.lineHeight;

        if(i!=0){
        measuredHeight +=mVertivalSpace;    
        }

    }
    setMeasuredDimension(measuredWidth, measuredHeight);
}

在MainActivity中:

public class MainActivity extends Activity {

    private FlowLayout layout;

    private String []mDatas={"单机游戏","美女","游戏","单机游戏","美女","淘宝","单机游戏","美女","淘宝","游戏" ,"单机游戏","淘宝","游戏","单机游戏","美女","淘宝","游戏","单机游戏","美女","淘宝","游戏" ,"有道","天猫","汽车商城","新闻","运动","熊出没之大逃跑"};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        layout=(FlowLayout) findViewById(R.id.flow_layout);
        layout.setPadding(10, 10, 10, 10);
        initData();
    }
    private void initData()
    {
        for(int i=0;i<mDatas.length;i++){
            TextView tv=new TextView(this);
            tv.setText(mDatas[i]);
            tv.setTextColor(Color.WHITE);
            tv.setGravity(Gravity.CENTER);
            tv.setBackgroundColor(Color.GRAY);
            tv.setPadding(3, 3, 3, 3);
            layout.addView(tv);
        }
    }
}

使用自定义布局时:

<ScrollView 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"
    tools:context="com.cca.frowlayout.MainActivity" >

    <com.cca.frowlayout.FlowLayout
        android:id="@+id/flow_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</ScrollView>

到这里,上图的效果就已经出来,这种布局的逻辑判断有点繁琐,稍有差错就显示不出来了。记得要多看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值