标题布局和自定义view进度条 及自定义ViewGroup

来源:互联网 发布:ubuntu 安装lnmp php7 编辑:程序博客网 时间:2024/05/17 06:04

写一个公用的标题布局


<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="horizontal" android:layout_width="match_parent"    android:background="@color/colorPrimary"    android:layout_height="wrap_content">    <TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:id="@+id/fh"        android:textColor="#fff"        android:layout_weight="1"        android:text="返回"/>    <TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="那些花儿"        android:gravity="center"        android:textColor="#fff"        android:layout_weight="1"        />    <TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:id="@+id/tj"        android:gravity="center"        android:textColor="#fff"        android:layout_weight="1"        android:text="提交"/></LinearLayout>
到Activity_main布局中引用

 <include layout="@layout/title"></include>

自定义View属性

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="MyFristView">        <attr name="color" format="color"></attr>        <attr name="radius" format="dimension"></attr>        <attr name="cx" format="dimension"></attr>        <attr name="cy" format="dimension"></attr>    </declare-styleable></resources>

自定义View

import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.RectF;import android.util.AttributeSet;import android.view.View;public class MyFristView extends View {    private Paint paint;    private float radius;    private float cx;    private float cy;    private float ss;    private int progress=2;    public MyFristView(Context context) {        this(context,null);    }    public MyFristView(Context context, AttributeSet attrs) {        super(context, attrs);        //画笔        paint = new Paint();        //设置画笔的属性        paint.setColor(Color.BLACK);        paint.setStrokeWidth(5);        paint.setStyle(Paint.Style.STROKE);        //获取自动View属性        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyFristView);        radius = array.getDimension(R.styleable.MyFristView_radius, 50);        cx = array.getDimension(R.styleable.MyFristView_cx, 300);        cy = array.getDimension(R.styleable.MyFristView_cy, 300);        //开启一个线程        new Thread(new Runnable() {            @Override            public void run() {                while (true){                    if(ss>360){                        break;                    }                    try {                        Thread.sleep(500);                        ss+=8;                        //刷新UI                        postInvalidate();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }).start();    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //画圆        canvas.drawCircle(cx,cy,radius,paint);        //画弧度        paint.setColor(Color.RED);        paint.setStrokeWidth(5);        RectF rect = new RectF(cx-radius,cy-radius,cx+radius,cy+radius);        canvas.drawArc(rect,-90,ss,false,paint);        //绘制文字         progress = (int) (ss / 360f * 100);        paint.setStrokeWidth(0);        paint.setColor(Color.BLACK);        paint.setTextSize(15);        canvas.drawText(progress-2+"%",cx-5,cy,paint);    }}
然后到第一activity布局中引用自定义view

<?xml version="1.0" encoding="utf-8"?><LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_frist"    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="com.example.shenxuesong.zoukao1105.FristActivity">    <include layout="@layout/title"></include>    <com.example.shenxuesong.zoukao1105.MyFristView        android:layout_width="500dp"        android:layout_height="500dp"        app:color="@color/colorAccent"        app:radius="100dp"        app:cx="200dp"        app:cy="200dp"        /></LinearLayout>
自定义ViewGroup

import android.content.Context;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;public class MyViewGroup extends ViewGroup{    private Context context;    public MyViewGroup(Context context) {        this(context,null);        this.context=context;    }    public MyViewGroup(Context context, AttributeSet attrs) {        super(context, attrs);        this.context=context;    }    @Override    public LayoutParams generateLayoutParams(AttributeSet attrs) {        return new MarginLayoutParams(context, attrs);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        //主动去测试子空间的宽高        measureChildren(widthMeasureSpec, heightMeasureSpec);        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b)    {        int cCount = getChildCount();        int cWidth = 0;        int cHeight = 0;        MarginLayoutParams cParams = null;        /**         * 遍历所有childView根据其宽和高,以及margin进行布局         */        for (int i = 0; i < cCount; i++)        {            View childView = getChildAt(i);            cWidth = childView.getMeasuredWidth();            cHeight = childView.getMeasuredHeight();            cParams = (MarginLayoutParams) childView.getLayoutParams();            int cl = 0, ct = 0, cr = 0, cb = 0;            switch (i)            {                case 0:                    cl = cParams.leftMargin;                    ct = cParams.topMargin;                    break;                case 1:                    cl = getWidth() - cWidth - cParams.leftMargin                            - cParams.rightMargin;                    ct = cParams.topMargin;                    break;                case 2:                    cl = cParams.leftMargin;                    ct = getHeight() - cHeight - cParams.bottomMargin;                    break;                case 3:                    cl = getWidth() - cWidth - cParams.leftMargin                            - cParams.rightMargin;                    ct = getHeight() - cHeight - cParams.bottomMargin;                    break;            }            cr = cl + cWidth;            cb = cHeight + ct;            childView.layout(cl, ct, cr, cb);        }    }}


然后到第二个activity布局中引用自定义view

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:orientation="vertical"    android:id="@+id/activity_second"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="com.example.shenxuesong.zoukao1105.SecondActivity">    <include layout="@layout/title"></include>      <com.example.shenxuesong.zoukao1105.MyViewGroup          android:layout_width="match_parent"          android:layout_height="wrap_content">          <Button              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:text="1"              />          <Button              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:text="2"/>          <Button              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:text="3"/>      </com.example.shenxuesong.zoukao1105.MyViewGroup></LinearLayout>

1、ViewGroup的职责是啥?

ViewGroup相当于一个放置View的容器,并且我们在写布局xml的时候,会告诉容器(凡是以layout为开头的属性,都是为用于告诉容器的),我们的宽度(layout_width)、高度(layout_height)、对齐方式(layout_gravity)等;当然还有margin等;于是乎,ViewGroup的职能为:给childView计算出建议的宽和高和测量模式 ;决定childView的位置;为什么只是建议的宽和高,而不是直接确定呢,别忘了childView宽和高可以设置为wrap_content,这样只有childView才能计算出自己的宽和高。

2、View的职责是啥?

View的职责,根据测量模式和ViewGroup给出的建议的宽和高,计算出自己的宽和高;同时还有个更重要的职责是:在ViewGroup为其指定的区域内绘制自己的形态。

3、ViewGroup和LayoutParams之间的关系?

大家可以回忆一下,当在LinearLayout中写childView的时候,可以写layout_gravity,layout_weight属性;在RelativeLayout中的childView有layout_centerInParent属性,却没有layout_gravity,layout_weight,这是为什么呢?这是因为每个ViewGroup需要指定一个LayoutParams,用于确定支持childView支持哪些属性,比如LinearLayout指定LinearLayout.LayoutParams等。如果大家去看LinearLayout的源码,会发现其内部定义了LinearLayout.LayoutParams,在此类中,你可以发现weight和gravity的身影。

2、View的3种测量模式

上面提到了ViewGroup会为childView指定测量模式,下面简单介绍下三种测量模式:

EXACTLY:表示设置了精确的值,一般当childView设置其宽、高为精确值、match_parent时,ViewGroup会将其设置为EXACTLY;

AT_MOST:表示子布局被限制在一个最大值内,一般当childView设置其宽、高为wrap_content时,ViewGroup会将其设置为AT_MOST;

UNSPECIFIED:表示子布局想要多大就多大,一般出现在AadapterView的item的heightMode中、ScrollView的childView的heightMode中;此种模式比较少见。

注:上面的每一行都有一个一般,意思上述不是绝对的,对于childView的mode的设置还会和ViewGroup的测量mode有一定的关系;当然了,这是第一篇自定义ViewGroup,而且绝大部分情况都是上面的规则,所以为了通俗易懂,暂不深入讨论其他内容。

3、从API角度进行浅析

上面叙述了ViewGroup和View的职责,下面从API角度进行浅析。

View的根据ViewGroup传人的测量值和模式,对自己宽高进行确定(onMeasure中完成),然后在onDraw中完成对自己的绘制。

ViewGroup需要给View传入view的测量值和模式(onMeasure中完成),而且对于此ViewGroup的父布局,自己也需要在onMeasure中完成对自己宽和高的确定。此外,需要在onLayout中完成对其childView的位置的指定。