美文网首页Android知识
Android之ACRA 和自定义布局

Android之ACRA 和自定义布局

作者: 破荒之恋 | 来源:发表于2016-12-26 11:40 被阅读71次

    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>
    

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

    相关文章

      网友评论

        本文标题:Android之ACRA 和自定义布局

        本文链接:https://www.haomeiwen.com/subject/hbdjvttx.html