【Android入门】融会贯通篇:结合上一个实例增加新技巧

一、新建针对美国、英国用户的BMI 

  • 改造计划

  1. 以原 BMI 应用程序为基础;
  2. 精简界面,只留下必要的功能;
  3. 将界面与文字消息由中文改成英文,以符合目标用户特性;
  4. 将计量单位由公制改为英制,并修改相关表达式;
  5. 改进身高的输入方式,由原本用一个“文字编辑文本框”(TextEdit)输入身高,改成用两个“下拉菜单”(Spinner)选择身高英尺、英寸。

res/layout/activity_main.xml

这里暂时使用前面“BMI”应用程序用到的“文字编辑字段”来直接输入英尺、英寸,以后再用下拉菜单组件来替换这两个字段

<?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:layout_width="fill_parent"
    android:layout_height="fill_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/us_height" />
    
    <EditText
        android:id="@+id/feet"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="" />

    <EditText
        android:id="@+id/inch"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/pound"/>

    <EditText
        android:id="@+id/weight"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text=""
        android:inputType="numberDecimal" />

    <Button
        android:id="@+id/submit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/bmi_btn"/>

    <TextView
        android:id="@+id/result"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:singleLine="true"
        android:text="" />

    <TextView
        android:id="@+id/suggest"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="" />

</LinearLayout>

res/value/string.xml

<resources>
    <string name="app_name">aBMI</string>
    <string name="app_label">BMI for the  British system</string>
    <string name="us_height">Height</string>
    <string name="feet_prompt">Select Feet</string>
    <string name="inch_prompt">Select Inches</string>
    <string name="pound">Weight (lbs)</string>
    <string name="bmi_btn">Calc BMI</string>
    <string name="bmi_result">Your BMI is ...</string>
    <string name="input_error">oops,you should type numbers only</string>
    <string name="advice_light">You should eat more</string>
    <string name="advice_average">You are in good shape,keep it!</string>
    <string name="advice_heavy">You should lose some weight</string>
    <string name="advice_fat">You should do something to improve your situation,right now</string>
    <string name="about_label">About...</string>
    <string name="about_title">About aBMI 1.0</string>
    <string name="about_msg">aBMI is a BMI calculator for the British system,written by sc</string>
    <string name="ok_label">OK</string>

    <string-array name="feets">
        <item>2 feet</item>
        <item>3 feet</item>
        <item>4 feet</item>
        <item>5 feet</item>
        <item>6 feet</item>
        <item>7 feet</item>
        <item>8 feet</item>
    </string-array>
    <string-array name="inches">
        <item>0 inches</item>
        <item>1 inches</item>
        <item>2 inches</item>
        <item>3 inches</item>
        <item>4 inches</item>
        <item>5 inches</item>
        <item>6 inches</item>
        <item>7 inches</item>
        <item>8 inches</item>
        <item>9 inches</item>
        <item>10 inches</item>
        <item>11 inches</item>
    </string-array>
</resources>

MainActivity.java

 在“aBMI应用程序”中,我们只保留了“关于...”(MENU_aBOUT)的选项,把另一个“结束”的选项移除了。在“关于...”页面中,也将连接首页的按钮移除了。

package com.demo.android.abmi;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.text.DecimalFormat;

//aBMI is for British system
public class MainActivity extends Activity {
    private static final String TAG = "aBmi";

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

    private Button button_calc;
    private EditText field_feet;
    private EditText field_inch;
    private EditText field_weight;
    private TextView view_result;
    private TextView view_suggest;

    private void findViews() {
        Log.d(TAG, "find Views");
        button_calc = (Button) findViewById(R.id.submit);
        field_feet = (EditText) findViewById(R.id.feet);
        field_inch = (EditText) findViewById(R.id.inch);
        field_weight = (EditText) findViewById(R.id.weight);
        view_result = (TextView) findViewById(R.id.result);
        view_suggest = (TextView) findViewById(R.id.suggest);
    }

    //Listen for button clicks
    private void setListensers() {
        Log.d(TAG, "set Listensers");
        button_calc.setOnClickListener(calcUsBMI);
    }

    private Button.OnClickListener calcUsBMI = new Button.OnClickListener() {
        @Override
        public void onClick(View view) {
            DecimalFormat nf = new DecimalFormat("0.00");
            try {
                double height = (Double.parseDouble(field_feet.getText().toString())*12+Double.parseDouble(field_inch.getText().toString()))*2.54/100;
                double weight = Double.parseDouble(field_weight.getText().toString())*0.45359;
                double BMI = weight / (height * height);
                //Present result
                view_result.setText(getText(R.string.bmi_result) + nf.format(BMI));

                //Give health advice
                if(BMI > 27) {
                    view_suggest.setText(R.string.advice_fat);
                } else if(BMI > 25) {
                    view_suggest.setText(R.string.advice_heavy);
                } else if(BMI < 20) {
                    view_suggest.setText(R.string.advice_light);
                } else {
                    view_suggest.setText(R.string.advice_average);
                }
            } catch (Exception obj) {
                Toast.makeText(MainActivity.this, getString(R.string.input_error), Toast.LENGTH_SHORT).show();
            }
        }
    };

    protected static final int MENU_ABOUT = Menu.FIRST;

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        Log.d(TAG, "open Menu");
        menu.add(0, MENU_ABOUT, 0, R.string.about_label);
        return true;
    }

    public boolean onOptionsItemSelected(MenuItem item) {
        super.onOptionsItemSelected(item);
        Log.d(TAG, "select Menu Item");
        switch (item.getItemId()) {
            case MENU_ABOUT:
                openOptionsDialog();
                break;
        }
        return true;
    }

    private void openOptionsDialog() {
        Log.d(TAG, "open Dialog");
        new AlertDialog.Builder(this)
                .setTitle(R.string.about_title)
                .setMessage(R.string.about_msg)
                .setPositiveButton(R.string.ok_label,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                            }
                        })
                .show();
    }
}

二、支持多国语言

  要让应用程序支持多个语言界面,不需要置换原有的语言界面。只需要在“res”目录下新建相应的语言目录,新建“res/values-en”来放“英文字符串”,新建“res/values-zh-rCN”来放“简体中文字符串”。

以“简体中文字符串”的“values-zh-rCN”目录名称命名方式为例,“zh”是主语系,“h”代表“中文”。“r”字母之后的“CN”是分支,表示“简体中文”。“r”是“revision”的意思。

values-zh-rCN/strings.xml

<resources>
    <string name="app_name">aBMI</string>
    <string name="app_label">BMI 英制计算器</string>
    <string name="us_height">身高</string>
    <string name="feet_prompt">选择英尺</string>
    <string name="inch_prompt">选择英寸</string>
    <string name="pound">体重 (lbs)</string>
    <string name="bmi_btn">计算 BMI 值</string>
    <string name="bmi_result">你的 BMI 值是</string>
    <string name="input_error">哦哦,字段中只能输入数字喔</string>
    <string name="advice_light">你该多吃点</string>
    <string name="advice_average">你的体型很不错喔,好好保持吧!</string>
    <string name="advice_heavy">你应该减肥啰!</string>
    <string name="advice_fat">为了健康,你应该马上采取一些行动啰!</string>
    <string name="about_label">关于...</string>
    <string name="about_title">关于 aBMI 1.0</string>
    <string name="about_msg">aBMI 是个 BMI 值计算器程序,由 sc 编写</string>
    <string name="ok_label">OK</string>

    <string-array name="feets">
        <item>2 英尺</item>
        <item>3 英尺</item>
        <item>4 英尺</item>
        <item>5 英尺</item>
        <item>6 英尺</item>
        <item>7 英尺</item>
        <item>8 英尺</item>
    </string-array>
    <string-array name="inches">
        <item>0 英寸</item>
        <item>1 英寸</item>
        <item>2 英寸</item>
        <item>3 英寸</item>
        <item>4 英寸</item>
        <item>5 英寸</item>
        <item>6 英寸</item>
        <item>7 英寸</item>
        <item>8 英寸</item>
        <item>9 英寸</item>
        <item>10 英寸</item>
        <item>11 英寸</item>
    </string-array>
</resources>
  • “values”目录名称,与改写后对应的支持语言关系如下
  1. 繁体中文:values-zh-rTW
  2. 简体中文:values-zh-rCN
  3. 日文:values-ja
  4. 英文:values-en
  5. 美式英文:values-en-rUS
  6. 英式英文:values-en-rUK
  • 切换语言

  切换手机设置的语言,应用程序会改成对应的语言

三、使用接口(Adapter)

  接口:负责转换数据源提供给界面组件的函数

  Android平台,不允许直接将字符串数组应用在界面组件中。界面菜单的项目,都得要靠接口来提供,这样做是“为了保持程序的弹性”。Android平台默认提供的接口类型有很多种,“ArraryAdapter”的作用是读入程序中已声明的数组,并转换成界面组件看得懂的接口组件。还有“SimpleAdapter”(从XML文字字符串文件读入数组)、“CursorAdapter”(从ContentProvider读入数组)等。

  • 数组接口(ArrayAdapter)与字符串数组

我们可以将字符串数组写入“res/values/string.xml”字符串文件,在“<resource>”标签中添加如下语句:

<resources>
    ...
    <string-array name="feets">
        <item>2 feet</item>
        <item>3 feet</item>
        <item>4 feet</item>
        <item>5 feet</item>
        <item>6 feet</item>
        <item>7 feet</item>
        <item>8 feet</item>
    </string-array>
    <string-array name="inches">
        <item>0 inches</item>
        <item>1 inches</item>
        <item>2 inches</item>
        <item>3 inches</item>
        <item>4 inches</item>
        <item>5 inches</item>
        <item>6 inches</item>
        <item>7 inches</item>
        <item>8 inches</item>
        <item>9 inches</item>
        <item>10 inches</item>
        <item>11 inches</item>
    </string-array>
</resources>

“string-array”组件可以提供“R.array.标识符”格式的参考资源。

 

在“MainActivity.java”文件中,定义“ArrayAdapter”

private void findViews() {
    ...
       ArrayAdapter<CharSequence> adapter_feet = ArrayAdapter.createFromResource(this, R.array.feets, android.R.layout.simple_spinner_item);
       adapter_feet.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

       ArrayAdapter<CharSequence> adapter_inch = ArrayAdapter.createFromResource(this, R.array.inches, android.R.layout.simple_spinner_item);
       adapter_inch.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    }

  “ArrayAdapter”接口使用“createFromResource”函数,接受3个参数。第1个参数是指定Activity,第2个参数指定“String.xml”字符串资源,第3个参数“android.R.layout.simple_spinner_item”为Android内置的默认下拉菜单选项格式。

  “setDropDownViewResource”方法用来定义下拉查看菜单(DropDownView)的格式

四、添加下拉菜单组件(Spinner)

修改 “res/layout/activity_main.xml”,添加Spinner

...
    <Spinner
        android:id="@+id/feet"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:drawSelectorOnTop = "true"
        android:prompt="@string/feet_prompt" />

    <Spinner
        android:id="@+id/inch"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:drawSelectorOnTop = "true"
        android:prompt="@string/inch_prompt" />
...

  我们将原本使用“TextEdit”界面组件的“@+id/feet”、“@+id/inch”两个字段,改为使用“Spinner”界面组件。

  android:drawSelectorOnTop = "true" 属性的作用是指定这个下拉菜单是否可以显示在其他菜单的上层。这个属性只有在多层菜单上才会显示出效果

  android:prompt 属性的作用是指定下拉菜单弹出菜单选项的提示语句(弹出菜单选项的标题)。

 

MainActivity.java

...
//    private EditText field_feet;
//    private EditText field_inch;
    private Spinner field_feet;
    private Spinner field_inch;
...

    private void findViews() {
        ...
//        field_feet = (EditText) findViewById(R.id.feet);
//        field_inch = (EditText) findViewById(R.id.inch);
        field_feet = (Spinner) findViewById(R.id.feet);
        field_inch = (Spinner) findViewById(R.id.inch);
        ...

        ArrayAdapter<CharSequence> adapter_feet = ArrayAdapter.createFromResource(this, R.array.feets, android.R.layout.simple_spinner_item);
        adapter_feet.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        field_feet.setAdapter(adapter_feet);

        ArrayAdapter<CharSequence> adapter_inch = ArrayAdapter.createFromResource(this, R.array.inches, android.R.layout.simple_spinner_item);
        adapter_inch.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        field_inch.setAdapter(adapter_inch);
    }

    //Listen for button clicks
    private void setListensers() {
        ...
        field_feet.setOnItemSelectedListener(getFeet);
        field_inch.setOnItemSelectedListener(getInch);
        ...
    }

    private int feet;
    private int inch;

    private Spinner.OnItemSelectedListener getFeet = new Spinner.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView parent, View v, int position, long id) {
            feet = parent.getSelectedItemPosition() + 2;
        }
        public void onNothingSelected(AdapterView parent) {
        }
    };
    private Spinner.OnItemSelectedListener getInch = new Spinner.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView parent, View v, int position, long id) {
            inch = parent.getSelectedItemPosition() + 1;
        }
        public void onNothingSelected(AdapterView parent) {
        }
    };

    private Button.OnClickListener calcUsBMI = new Button.OnClickListener() {
        @Override
        public void onClick(View view) {
          ...
                double height = (feet * 12 + inch) * 2.54 / 100;
                double weight = Double.parseDouble(field_weight.getText().toString())*0.45359;
                double BMI = weight / (height * height);
                //Present result
                view_result.setText(getText(R.string.bmi_result) + nf.format(BMI));
          ...
        }
    };
  ...
}        

  在“findViews”函数中,声明了“field_feet”、“field_inch”两个“Spinner”界面组件,和“adapter_feet”、“adapter_inch”两个接口。最后“field_feet”组件加上“setAdapter”函数,将界面组件与接口接在一起,这样下拉菜单(Spinner)通过接口显示String.xml定义的数组。

  在“setListensers”函数中,“field_feet”下拉菜单的“setOnItemSelectedListener”方法负责设置按下“Spinner”菜单后续动作的函数,范例中方法参数“getFeet”函数来完成进一步的处理。

  自定义函数“getFeet”函数,函数类型“Spinner.OnItemSelectedListener”,在“OnItemSelectedListener”里面定义一个“onItemSelected”函数与另一个“onNothingSelected”函数。

  “onItemSelected”函数默认传入参数有4个,第1个参数是你当前操作的下拉菜单实体“Spinner”;第2个参数对于手机App开发用处不大;第3个参数是“Spinner”选项选中的位置,一般自上而下从0开始;第4个参数是你选中的某个Spinner中的某个下来值所在的行,也是自上而下从0开始,一般只有在从数据表中取得的数据时,才会使用到。

本例语句“feet = parent.getSelectedItemPosition() + 2;”,“getSelectedItemPosition()”获取的“position”从0开始。而我们的项目“string-array”从“2 feet”开始,值从2开始。为了方便计算“feet 变量”,所以“+2”,这样以后存储的“feet 变量”的值就从2开始。

  “onNothingSelected”函数则是处理用户什么选项都没有选的情况。当我们将函数内容留下空白,表示当用户什么选项都没选时,不作处理。

 

posted @ 2019-07-20 22:21  哈撒king  阅读(230)  评论(0编辑  收藏  举报