1. 程式人生 > >菜鳥流程-Touching App(1)- 主介面

菜鳥流程-Touching App(1)- 主介面

接下來我會把自己寫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 / 720);
        params2.height = (int) (65.95 * mScreenHeight / 1280);
        btn_left.setX(58.1f * mScreenWidth / 720.0f);
        btn_left.setY(51.0f * mScreenHeight / 1280.0f);
        btn_left.setLayoutParams(params2);

這個是對左邊設定按鈕的調整,右邊的類似,就不上了,真有想看我程式碼的同學或者大牛可以在下面下載到~

然後上一下最終的效果圖:
這裡寫圖片描述
在320*480px的虛擬機器上跑也是這個效果哦,hiahiahia~

好了,這個主介面好像差不多了,,

說老實話,寫部落格還是有點累的,比寫程式碼麻煩。。