首页 > 代码库 > 菜鸟流程-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~
好了,这个主界面好像差不多了,,
说老实话,写博客还是有点累的,比写代码麻烦。。
界面源码下载地址:
http://download.csdn.net/download/qq_21922801/9615690
菜鸟流程-Touching App(1)- 主界面