菜鸟流程-Touching App- 主界面

Posted 七夕哒

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了菜鸟流程-Touching App- 主界面相关的知识,希望对你有一定的参考价值。

接下来我会把自己写Touching App的过程一一写下来,不过由于刚上路,可能还有很多错误,包括博客也是~~ 小事情啦,开心就好n(≧▽≦)n

这个app准备用来接收单片机传来的数据,然后显示在手机上,对环境进行评价。

下面进入正题啦。

一、界面元素分析

先看一下美工给我的图:

美工主界面 图片

是基于常见的1280*720像素的图片。

很显然,这个图片是有三部分构成的,上面的按钮层,中间的圆环,底部的数据展示。最难的应该是中间的圆环,所以我是先从这一部分开始的。


二、主界面_中部圆环实现

其实写过了之后回头看还是很简单,虽然好像本来就不难、、、
需要实现的是一个自定义view,外面一个大的黑色圆环,里面一个小的彩色圆环,中间是接收到的数据,暂时让数据一直增加。

2.1 先来实现中间的圆环吧

效果是这样的

中部圆环图片

其实也很简单,稍微困难一点的地方在于外发光和位置的选择,下面上代码,然后一步步说。

package com.example.blogcircle;

import android.content.Context;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;


public class MyCircle extends View {

    private  int CircleWidth = 10; //圆环的宽度
    private int mCircleRadius = 223;// 圆环半径

    private static int mBlurRadius = 10;//外发光半径
    private static android.graphics.BlurMaskFilter.Blur mBlurStyle = android.graphics.BlurMaskFilter.Blur.SOLID;//外发光方式

    private Paint mBackCirclePaint;//黑环画笔
    private Paint mFrontCirclePaint;//彩环画笔

    public MyCircle(Context context, AttributeSet attrs,
            int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

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

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

    public void init() {
        //初始化黑环画笔
        mBackCirclePaint = new Paint();
        mBackCirclePaint.setAntiAlias(true);
        mBackCirclePaint.setColor(0xFF000000);
        mBackCirclePaint.setStyle(Paint.Style.STROKE);
        mBackCirclePaint.setStrokeWidth(CircleWidth);

        //初始化彩环画笔
        mFrontCirclePaint = new Paint();
        mFrontCirclePaint.setAntiAlias(true);
        mFrontCirclePaint.setColor(0xFF47B7FF);
        mFrontCirclePaint.setStyle(Paint.Style.STROKE);
        mFrontCirclePaint.setStrokeWidth(CircleWidth);
        mFrontCirclePaint.setMaskFilter(new BlurMaskFilter(mBlurRadius,
                mBlurStyle));
    }


    @Override
    protected void onDraw(Canvas canvas) {
        init();
        super.onDraw(canvas);

        float rectL = 360 - mCircleRadius
                - CircleWidth / 2;
        float rectT = 501 - mCircleRadius
                - CircleWidth / 2;
        float rectR = 360 + mCircleRadius
                + CircleWidth / 2;
        float rectB = 501 + mCircleRadius
                + CircleWidth / 2;


        // 画背后的黑色圆环
        RectF rectCircle1 = new RectF(rectL, rectT, rectR, rectB);
        Path path1 = new Path();
        path1.addArc(rectCircle1, 0, 360);
        canvas.drawPath(path1, mBackCirclePaint);


        // 画前面的彩色圆环
        Path path2 = new Path();
        path2.addArc(rectCircle1, -90, 90);
        canvas.drawPath(path2, mFrontCirclePaint);

    }

}

在这一部分暂时没有考虑那么多,位置什么直接根据美工给的图算出来的距离,主要是实现了彩色圆环的外发光。
在实现外发光的时候其实只需要添加一排代码就够了,就是在初始化彩色画笔的那里。

mFrontCirclePaint.setMaskFilter(new BlurMaskFilter(mBlurRadius,
                mBlurStyle));

但是这里还有个坑,当时坑了我好久,那就是要关闭硬件加速,要不然没有外发光的效果,需要在manifest文件中进行关闭。
下面是manifest文件中activity部分的代码,核心也就是一句:

<activity                  
    android:name="com.example.blogcircle.MainActivity"
    android:label="@string/app_name" 
    android:hardwareAccelerated="false"        >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />                
        <category   android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

到这里呢,就实现了中间有圆环了。

2.2 然后加上中间的数字以及下面的英文评价

效果图是下面这样的
这里写图片描述

其实这里应该放一个动图,不过我不会、、、
就是数字从0到100不停变化,彩色圆环随数字的变化而变化,下面的单词也在变化。

难点呢,就是数字的变化因为是模拟从单片机接收数据,所以应该放在另一个类里面进行变化,然后传给自定义View类。另一个难点就是数字和字母的居中显示,因为字母的长度,数字的长度在变化,所以不能用硬性的位置来计算了。

不管怎么样,先上完整代码,再说说我觉得坑的地方。

package com.example.blogcircle;

import android.content.Context;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;


public class MyCircle extends View {

    private  int CircleWidth = 10; //圆环的宽度

    private int mCircleRadius = 223;// 圆环半径
    private static int mBlurRadius = 10;
    private static android.graphics.BlurMaskFilter.Blur mBlurStyle = android.graphics.BlurMaskFilter.Blur.SOLID;

    private static int mNUM = 0;// 单片机传进来的数值
    private static String[] mLevel = { "unbearable", "bad", "soso", "easy",
            "comfort", "comfort" };

    private Paint mBackCirclePaint;
    private Paint mFrontCirclePaint;

    private Paint mNumPaint;
    private Paint mTextPaint;

    public MyCircle(Context context, AttributeSet attrs,
            int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

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

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

    public void init() {

        mBackCirclePaint = new Paint();
        mBackCirclePaint.setAntiAlias(true);
        mBackCirclePaint.setColor(0xFF000000);
        mBackCirclePaint.setStyle(Paint.Style.STROKE);
        mBackCirclePaint.setStrokeWidth(CircleWidth);

        mFrontCirclePaint = new Paint();
        mFrontCirclePaint.setAntiAlias(true);
        mFrontCirclePaint.setColor(0xFF47B7FF);
        mFrontCirclePaint.setStyle(Paint.Style.STROKE);
        mFrontCirclePaint.setStrokeWidth(CircleWidth);
        mFrontCirclePaint.setMaskFilter(new BlurMaskFilter(mBlurRadius,
                mBlurStyle));

        int textSize=150;
        mNumPaint=new Paint();
        mNumPaint.setAntiAlias(true);
        mNumPaint.setColor(0xFFFFFFFF);
        mNumPaint.setTextSize(textSize);

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setColor(0xFFAAAAAA);
        textSize=40;
        mTextPaint.setTextSize(textSize);

    }


    @Override
    protected void onDraw(Canvas canvas) {
        init();
        super.onDraw(canvas);

        float rectL = 360 - mCircleRadius
                - CircleWidth / 2;
        float rectT = 501 - mCircleRadius
                - CircleWidth / 2;
        float rectR = 360 + mCircleRadius
                + CircleWidth / 2;
        float rectB = 501 + mCircleRadius
                + CircleWidth / 2;


        // 画背后的黑色圆环
        RectF rectCircle1 = new RectF(rectL, rectT, rectR, rectB);
        Path path1 = new Path();
        path1.addArc(rectCircle1, 0, 360);
        canvas.drawPath(path1, mBackCirclePaint);


        // 画前面的彩色圆环
        Path path2 = new Path();
        path2.addArc(rectCircle1, -90,  (int) (mNUM * 3.6));
        canvas.drawPath(path2, mFrontCirclePaint);

        // 数字居中:y就是 矩形中间的y值加上文字的descent,x就是 矩形中间的x值减去数字宽度的一半
        float numDescent=mNumPaint.getFontMetrics().descent;
        canvas.drawText(mNUM + "", 
            360 -mNumPaint.measureText(mNUM + "") / 2,
            501 + numDescent, 
            mNumPaint);
        // 文字居中,y就是数字的y加上数字的descent加上文字的ascent,x就是矩形中间的x值减去文字宽度的一半
        canvas.drawText(mLevel[mNUM / 20],
        360 - mTextPaint.measureText(mLevel[mNUM / 20]) / 2, 
        501+ numDescent * 2 -TextPaint.getFontMetrics().ascent,
        mTextPaint);
}

    public void setNum(int num) {
        mNUM = num;
        invalidate();

    }
}

先说init()方法。
增加了两个画笔,分别用来画数字和字母。
在变量里面有一个mNum,模拟单片机传进来的数值。
同时在变量里面声明了一个数组,用来对应不同等级环境的评价,bad,soso这些,本来应该是只有五级的,不过我担心数组溢出什么的,给它多弄了一个,不影响。

再说onDraw()方法里面的数字居中和文字居中部分。
首先当然是把它们画出来。
直接用canvas的drawText方法

void android.graphics.Canvas.drawText(String text, float x, float y, Paint paint)

里面有四个参数,分别是要画的文本,文本起始位置,基准线的位置,所使用的画笔。(可能有些不对的地方、、大家指出来就好,不要喷我~)
关键就是计算文本的x,y值。
x呢,就是屏幕中部减去文本宽度的一半,这样在水平方向就居中了,怎么实现的代码上也有。
y呢,就是在圆环中部的y值加上文本的descent距离。
关于文字的一些距离,我百度了很久,找到了这么一个图。
这里写图片描述
图片引用网址是这个:http://mikewang.blog.51cto.com/3826268/871765/
(引用别人的图之后这样说不知道是不是合适、、感觉真的写起博客来好多问题啊-_-!)

其实我想加的不是这里的这个descent,是它上面的那一个,英文字母分布在四线格里,基准线是第三根线,所以想让文字垂直居中,应该是中间的y值加上一格的长度,不过呢,恰好就是这个descent值,所以就是这样了。

目前为止解决了为止问题,还有数字变化和圆环变化问题,圆环变化其实代码也就一句话。

// 画前面的彩色圆环
        Path path2 = new Path();
        path2.addArc(rectCircle1, -90, (int) (mNUM * 3.6));
        canvas.drawPath(path2, mFrontCirclePaint);

就是中间那句话,因为addArc()方法的三个参数分别是指矩形区域,开始的角度(从左向右水平为0度),和扫过的角度。因为数值为0对应-90度,100对应360度,所以只需要扫过代码中描述的那个值就可以了。

那这一部分剩下的就只有数字不停变化这个功能了。
在自定义View里面,对应的方法是setNum()。

    public void setNum(int num) {
        mNUM = num;
        invalidate();
    }

这个方法是给其他类用的,因为数值是从其他类传进来的,在方法里面设置好数值之后,立马调用invalidate()更新UI。

接来下就要看一下MainActivity这个类里面的代码了。
完整的代码是下面这样的。

package com.example.blogcircle;

import java.util.Timer;
import java.util.TimerTask;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {

    Handler mHandler;
    TimerTask task;
    Timer timer;
    int mNum = 0;// 中间圆圈的值
    MyCircle myCircle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myCircle=(MyCircle)findViewById(R.id.myCircle);

        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                // TODO Auto-generated method stub
                if (msg.what == 0x123) {
                    myCircle.setNum(mNum);
                }

                super.handleMessage(msg);
            }

        };
        task = new TimerTask() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                // 将单片机的数值赋给mNUM
                mNum = getNum();

                Message msg = new Message();
                msg.what = 0x123;
                mHandler.sendMessage(msg);
            }
        };
        if(timer==null)
        timer = new Timer();
        timer.schedule(task, 1000, 200);

    }

 // 得到单片机传进来的数值
    protected int getNum() {
        if (mNum > 99) {
            mNum = 0;
        } else {
            mNum++;
        }
        return mNum;
    }
}

这里只要onCreate()方法和getNum()方法。

先说简单的,getNum()方法我打算后期完善的,就是模拟从单片机获得数值,所以这里就让类变量mNum不停加1,模拟的还是很到位滴。也很简单,不说了。

再就是onCreate()方法了。思路就是,首先找到xml布局里的Mycircle控件,然后通过定时器不停的调用getNum()方法来使类变量mNum加1,而每次加1的同时会发送消息,调用MyCircle类的setNum变量,触发里面的invalidate,这样就达到了不停加1,不停更新UI的效果。

代码里面就是Timer,Task,Handler三个的配合,感觉很常用,百度一下就会了~~

好,这样就差不多已经实现了大部分了,不过我给的效果图都是真机上的效果图,当我打开xml的图形界面的时候感觉头很疼,因为它是这样的:
这里写图片描述

因为我的位置啊,距离啊全都是直接给的值,只能用在1280*720这个屏幕里面。

2.3 接下来到了关键环节了,也就是实现屏幕适配

我在这个环节遇到了好几个坑

首先,是如何实现屏幕适配
关于这个问题,我百度了很久,什么屏幕密度啊,屏幕分辨率啊,dip,dpi,dp,px乱七八糟的好多。。之后看到网上说,网页的前端没有这个问题是因为它们按照百分比写的界面,然后我决定这样做。

首先获取真实屏幕的宽度和高度,像素为单位。然后在代码里面按照比例进行缩放,eg,如果在宽720px的屏幕里面距离为10px,那么在360px里面距离应该为5px,代码为int margin=10*/720*360;

下面先上整个修改过后的,应该、适配屏幕的代码。

package com.example.blogcircle;

import android.content.Context;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;

public class MyCircle extends View {

    private  int CircleWidth = 10;
    private  int TextSize = 200;

    private final float WeightOfTitle = 0.09f;// 顶部栏所占高度权重
    private final float WeightOfView = 0.6f;// 自定义view所占高度权重

    private final float WeightOfCenterX = 0.5f;
    private final float WeightOfCenterY = 501.0f / 1280.0f;

    private int mCircleRadius = 223;// 圆环半径

    private int mScreenWidth;
    private int mScreenHeight;

    Typeface mTypeFace;

    private static int mNUM = 0;// 单片机传进来的数值
    private static String[] mLevel = { "unbearable", "bad", "soso", "easy",
            "comfort", "comfort" };

    private static int mBlurRadius = 10;
    private static android.graphics.BlurMaskFilter.Blur mBlurStyle = android.graphics.BlurMaskFilter.Blur.SOLID;

    private Paint mBackCirclePaint;
    private Paint mFrontCirclePaint;
    private Paint mNumPaint;
    private Paint mTextPaint;

    public MyCircle(Context context, AttributeSet attrs,
            int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // TODO Auto-generated constructor stub
    }

    public MyCircle(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }

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

    public void init() {
        DisplayMetrics dm = getResources().getDisplayMetrics();
        mScreenWidth = dm.widthPixels;
        mScreenHeight = dm.heightPixels;
        if((mScreenHeight/mScreenWidth)>(1280/720)){
            mCircleRadius=223*mScreenWidth/720;//圆环半径的适配
        }else{
            mCircleRadius=223*mScreenHeight/1280;
        }

        CircleWidth=Math.min(10*mScreenHeight/1280, 10*mScreenWidth/720);//圆环宽度的适配

        mBackCirclePaint = new Paint();
        mBackCirclePaint.setAntiAlias(true);
        mBackCirclePaint.setColor(0xFF000000);
        mBackCirclePaint.setStyle(Paint.Style.STROKE);
        mBackCirclePaint.setStrokeWidth(CircleWidth);

        mFrontCirclePaint = new Paint();
        mFrontCirclePaint.setAntiAlias(true);
        mFrontCirclePaint.setColor(0xFF47B7FF);
        mFrontCirclePaint.setStyle(Paint.Style.STROKE);
        mFrontCirclePaint.setStrokeWidth(CircleWidth);
        mFrontCirclePaint.setMaskFilter(new BlurMaskFilter(mBlurRadius,
                mBlurStyle));

        mNumPaint = new Paint();
        mNumPaint.setAntiAlias(true);
        mNumPaint.setColor(0xFFFFFFFF);

        int textSize=150*mCircleRadius/223;//数字大小的适配
        mNumPaint.setTextSize(textSize);

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setColor(0xFFAAAAAA);
        textSize=40*mCircleRadius/223;//英语大小的适配
        mTextPaint.setTextSize(textSize);

    }


    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        init();
        super.onDraw(canvas);

        float rectL = mScreenWidth * WeightOfCenterX - mCircleRadius
                - CircleWidth / 2;
        float rectT = mScreenHeight * WeightOfCenterY - mCircleRadius
                - CircleWidth / 2;
        float rectR = mScreenWidth * WeightOfCenterX + mCircleRadius
                + CircleWidth / 2;
        float rectB = mScreenHeight * WeightOfCenterY + mCircleRadius
                + CircleWidth / 2;

        // 画背后的黑色圆环
        RectF rectCircle1 = new RectF(rectL, rectT, rectR, rectB);
        Path path1 = new Path();
        path1.addArc(rectCircle1, 0, 360);
        canvas.drawPath(path1, mBackCirclePaint);

        Path path2 = new Path();
        path2.addArc(rectCircle1, -90, (int) (mNUM * 3.6));//
        canvas.drawPath(path2, mFrontCirclePaint);

        // 数字居中:y就是 矩形中间的y值加上文字的descent,x就是 矩形中间的x值减去数字宽度的一半
        canvas.drawText(
                mNUM + "",
                mScreenWidth * WeightOfCenterX
                        - mNumPaint.measureText(mNUM + "") / 2, mScreenHeight
                        * WeightOfCenterY + mNumPaint.getFontMetrics().descent,
                mNumPaint);
        float numDescent = mNumPaint.getFontMetrics().descent;
        // 文字居中,y就是数字的y加上数字的descent加上文字的ascent,x就是矩形中间的x值减去文字宽度的一半
        canvas.drawText(
                mLevel[mNUM / 20],
                mScreenWidth * WeightOfCenterX
                        - mTextPaint.measureText(mLevel[mNUM / 20]) / 2,
                mScreenHeight * WeightOfCenterY + numDescent * 2
                        - mTextPaint.getFontMetrics().ascent, mTextPaint);
    }

    public void setNum(int num) {
        mNUM = num;
        invalidate();

    }


}

我感觉这里主要就是思路的问题,直接提取两三句出来看看就好。

//1、直接算出比重的,以1280*720为基准。
private final float WeightOfCenterY = 501.0f / 1280.0f;
//2、直接进行变化的,根据现有屏幕和1280*720屏幕的比例。
if((mScreenHeight/mScreenWidth)>(1280/720)){
            mCircleRadius=223*mScreenWidth/720;//圆环半径的适配
        }else{
            mCircleRadius=223*mScreenHeight/1280;
        }
//3、其实和上面一种一样
int textSize=150*mCircleRadius/223;//数字大小的适配

其实都一样、就是以1280*720为基础进行缩放。

好了, 那屏幕适配这个坑就完成啦,哈哈哈哈。

接着,我发现在自定义view下面添加新的部件,在ui上看不见

比如我xml里面有个自定义View了,在下面紧接着来一个TextView,TextView会看不到。

这个着实坑了我有点久,结果发现就是自定义View的绘制流程不熟悉。。。
没有重写onMeasure()方法、、
这个方法是子部件用来告诉父部件“我需要多大的地方”的方法,如果没有重写的话,当自定义view没有规定特定大小的时候,会填充整个父类。
由于我没有重写,所以放在它下面的textView在屏幕之外,当然是看不到的,知道原因就好说了,直接修改代码就ok啦,上修改的部分代码。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // TODO Auto-generated method stub
    setMeasuredDimension(measureWidth(widthMeasureSpec),// 600);
            measuredHeight(heightMeasureSpec));
    //Log.i("qx", "height:"+measuredHeight(heightMeasureSpec));
}

private int measuredHeight(int heightMeasureSpec) {
    // TODO Auto-generated method stub
    int result = 0;
    int specMode = MeasureSpec.getMode(heightMeasureSpec);
    int specSize = MeasureSpec.getSize(heightMeasureSpec);
    if (specMode == MeasureSpec.EXACTLY) {
        result = specSize;
    } else {
        result = (int) (mScreenHeight * WeightOfView);
        if (specMode == MeasureSpec.AT_MOST)
            result = Math.min(result, specSize);
    }

    return result;
}

private int measureWidth(int widthMeasureSpec) {
    // TODO Auto-generated method stub
    DisplayMetrics dm = getResources().getDisplayMetrics();
    mScreenWidth = dm.widthPixels;
    mScreenHeight = dm.heightPixels;


    int result = 0;
    int specMode = MeasureSpec.getMode(widthMeasureSpec);
    int specSize = MeasureSpec.getSize(widthMeasureSpec);

    if (specMode == MeasureSpec.EXACTLY) {
        result = specSize;
    } else {
        result = mScreenWidth;
        if (specMode == MeasureSpec.AT_MOST)
            result = Math.min(result, specSize);
    }

    return result;
}

对于这个方法细致的讲解呢、、这篇博客里面还是不要讲好了,,我只是想概览的讲述一下写小项目的经历,也许以后会发真正的技术贴。

不过,只需要知道这样写了之后,这个自定义view只会包裹它该包裹的区域就好了。


三、主界面_底部数据和顶部按钮

由于写中部圆环的时候,吃了个亏,关于屏幕匹配的,所以我决定打死不用硬性的距离,包括dp也不用了,坚决拥护百分比制度。
所以我现在特别喜欢LinearLayout这个布局,因为它有weight这个属性~~
直接上布局代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FF1E2E3E"
    tools:context=".MainActivity" >

    <ImageButton
        android:id="@+id/ibtn_left"
        android:scaleType="fitXY" 
         android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:background="@drawable/left_selector"
        />



    <ImageButton
        android:id="@+id/ibtn_right"
        android:scaleType="fitXY" 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:background="@drawable/right_selector" />

    <myView.MyViewCircleAdaption
        android:id="@+id/myview_circle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <!-- 蓝色的分割线 -->

    <View
        android:id="@+id/line"
        android:layout_width="fill_parent"
        android:layout_height="1dp"
        android:layout_below="@id/myview_circle"
        android:layout_marginTop="20dp"
        android:background="#FF47B7FF" />

    <!-- 下方的数据展示界面 -->

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/line"
        android:background="@drawable/background_color"
        android:orientation="vertical"
        android:weightSum="7" >

        <!-- 空白 透明背景 -->

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="2" >

            <TextView
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:background="#00000000" />
        </LinearLayout>

        <!-- 水平展示,两个数字数据 -->

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:gravity="center_vertical"
            android:orientation="horizontal" >

            <!-- 左空白 -->

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="3"
                android:background="#000000FF" />
            <!-- 温度 -->
            <!-- 数字 温度 -->

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="vertical" >

                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:orientation="horizontal" >

                    <TextView
                        android:id="@+id/tem"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:background="#00000000"
                        android:text="25 "
                        android:textColor="#FFFFFFFF"
                        android:textSize="30sp" />
                    <!-- 单位 温度 -->

                    <TextView
                        android:id="@+id/tem_danwei"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:alpha="0.5"
                        android:background="#00000000"
                        android:text="°C"
                        android:textSize="30dp" />
                </LinearLayout>

                <TextView
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:background="#00000000"
                    android:text="Temprature"
                    android:textSize="15sp" />
            </LinearLayout>
            <!-- 中间空白 -->

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="4"
                android:background="#000000FF" />
            <!-- 湿度 -->

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="vertical" >

                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:orientation="horizontal" >

                    <!-- 数字 湿度 -->

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:background="#00000000"
                        android:text="75 "
                        android:textColor="#FFFFFFFF"
                        android:textSize="30dp" />

                    <!-- 单位  湿度 -->

                    <TextView
                        android:id="@+id/shidu"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:alpha="0.5"
                        android:background="#00000000"
                        android:text="%RH"
                        android:textSize="30dp" />
                </LinearLayout>

                <TextView
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:background="#00000000"
                    android:gravity="center_horizontal"
                    android:text="Humicity"
                    android:textSize="15sp" />
            </LinearLayout>
            <!-- 右空白 -->

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="2"
                android:background="#000000FF" />
        </LinearLayout>

        <!-- 水平展示,一个按钮 -->

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:gravity="center" >

            <Button
                android:id="@+id/button_details"
                android:layout_width="191px"
                android:layout_height="57px"
                android:background="@drawable/button_selector"
                android:text="details"
                android:gravity="center"
                android:textColor="#ff37a7eF"
                android:textSize="20dp" />
        </LinearLayout>
    </LinearLayout>


</RelativeLayout>

顶部的按钮由于父组件是Relativelayout,不太方便直接在xml里面进行调整,要是用dp的话,对屏幕又不太适配了,所以我在java代码里面对它们进行了调整。就是下面这样:

btn_left = (ImageButton) findViewById(R.id.ibtn_left);
        LayoutParams params2 = (LayoutParams) btn_left.getLayoutParams();
        params2.width = (int) (65.95 * mScreenWidth

以上是关于菜鸟流程-Touching App- 主界面的主要内容,如果未能解决你的问题,请参考以下文章

Android app开发流程都有哪些环节

WPF菜鸟问题:在登录窗体有Textbox1用于输入用户名,在主界面窗体有一个label1

课程管理系统菜鸟教学

ios app上架流程

Android 插件化VirtualApp 安装并启动资源中自带的 APK 插件 ( 添加依赖库 | 准备插件 APK | 启动插件引擎 | 拷贝 APK 插件 | 安装插件 | 启动插件 )(代码片

Android 插件化VirtualApp 安装并启动资源中自带的 APK 插件 ( 添加依赖库 | 准备插件 APK | 启动插件引擎 | 拷贝 APK 插件 | 安装插件 | 启动插件 )(代码片