Страницы

вторник, 19 августа 2014 г.

Пересчет температуры

Программа для пересчета температуры (приложение для Android)

Разработаем очень простое приложение для Android - программу пересчета температуры, измеренной по шкале Цельсия, в температуру по шкалам Фаренгейта и Реомюра.
Формулы пересчета:

1) T°F=(9/5T + 32)°C

2) T°C=(4/5T )°R

Поскольку сама программа получается очень простая, потренируемся заодно работать с фрагментами. Ввод данных будет расположен в одном фрагменте, а вывод результатов – в другом. Сделаем разную разметку для альбомной и портретной ориентации. Предусмотрим сохранение информации в текстовых полях после смены ориентации экрана.

У вас должна быть установлена среда разработки, например, Eclipse, а также Android SDK.
Создаем новый проект


Создание проекта Android

Создание проекта Android

Далее выбираем иконку для приложения. Можно выбрать готовую из клипарта, а можно сделать свою (я нарисовал свою).


Создание проекта Android

Затем выбираем Blank Activity (пустое окно).  Имя активности (Activity) можно оставить по умолчанию.
Если выбрать Blank Activity with Fragment, то будет создан фрагмент и добавлен к активности. Но мы это сделаем сами.
После создания проекта активность выглядит так:



Удалим поле с «HelloWorld».
Создадим новые текстовые ресурсы (файл strings.xml  в папке values).
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Пересчет температуры</string>
    <string name="action_settings">Settings</string>
    <string name="txtPrompt">Введите температуру в градусах Цельсия</string>
    <string name="txtC">Температура по Цельсию</string>
    <string name="txtF">Температура по Фаренгейту</string>
    <string name="txtR">Температура по Реомюру</string>
    <string name="btnCalc">Вычислить</string>
    <string name="btnExitCaption">Выход</string>
<string name="menu_exit">Выход</string>

</resources>
Это названия текстовых полей, надписи на кнопках и пункты меню.
Создадим еще один xml-файл в этой папке. Идем File->New->Other, в появившемся окне выбираем Android XML file:


Пишем название файла (colors)


Текст файла (цвета можете выбрать сами, я взял первые попавшиеся):
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <color name="colorBack">#42DAE5</color>
    <color name="white_color">#FFFFFF</color>

</resources>
Это цвет фона и цвет поля для ввода текста.
Сейчас нам нужно создать два файла с разметкой фрагментов и два файла с текстом программы.
Переходим в папку layout и выбираем File->New->Other, затем выбираем файл разметки:

 

Затем пишем название файла (fragment1) и завершаем работу мастера.
Затем копируем его и вставляем в эту же папку, переименовываем при копировании во fragment2.xml.
Затем добавим текстовые поля и две кнопки. Можно все это добавлять с помощью панели инструментов, а можно просто скопировать xml-текст.
Разметка первого фрагмента:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:gravity="center_horizontal"
        android:text="@string/txtPrompt" />

    <EditText
        android:id="@+id/edC"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="5dp"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:background="@color/white_color"
        android:ems="10"
        android:inputType="numberSigned|numberDecimal">

        <requestFocus />
    </EditText>

    <Button
        android:id="@+id/btnCalcul"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:text="@string/btnCalc" />

    <Button
        android:id="@+id/btnExit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="@string/btnExitCaption" />

</LinearLayout>
Результат:


Разметка второго фрагмента
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:gravity="center_horizontal"
        android:text="@string/txtF" />

    <TextView
        android:id="@+id/tvF"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_margin="5dp"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:background="@color/white_color" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:gravity="center_horizontal"
        android:text="@string/txtR" />

    <TextView
        android:id="@+id/tvR"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_margin="5dp"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:background="@color/white_color" />

</LinearLayout>
Результат


Создадим два java-файла фрагментов. Каждый фрагмент будет выполнять свою задачу (один – ввод данных, другой – вывод) и не должен знать о других фрагментах приложения. Координацию между ними выполняет activity, как слушатель нажатия кнопки расчета.
Создаем новый java-class.


Пишем название файла, наследуемся от класса Fragment из библиотеки поддержки - android.support.v4.app.Fragment.
Код первого фрагмента fragment1.java:
package ru.studentshelper.fahrenheit1;

import ru.studentshelper.fahrenheit1.R;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class fragment1 extends Fragment implements OnClickListener {
    double tCelsius;
    private EditText edC;

    public interface OnbtnCalcClickListener {
        void onBtnCalcClick(double tCels);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        // return super.onCreateView(inflater, container, savedInstanceState);
        View viewHierarchy = inflater.inflate(R.layout.fragment1, container,
                false);
        Button btnCalcul = (Button) viewHierarchy.findViewById(R.id.btnCalcul);
        Button btnExit = (Button) viewHierarchy.findViewById(R.id.btnExit);
        btnCalcul.setOnClickListener(this);
        btnExit.setOnClickListener(this);
        ;
        edC = (EditText) viewHierarchy.findViewById(R.id.edC);
        return viewHierarchy;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btnExit:
            getActivity().finish();
            break;
        case R.id.btnCalcul:
            // TODO Auto-generated method stub
            if (edC.getText().length() != 0) {
                tCelsius = Double.parseDouble(edC.getText().toString());
                OnbtnCalcClickListener listener = (OnbtnCalcClickListener) getActivity();
                listener.onBtnCalcClick(tCelsius);
            } else {
                Toast.makeText(getActivity(), "Не введена температура!",
                        Toast.LENGTH_SHORT).show();
                return;
            }
            break;
        }
    }
}
Добавляем implements OnClickListener, то есть делаем слушателем кнопки фрагмент.
Создаем интерфейс OnbtnCalcClickListener с одной функцией, которую только объявляем, но не реализуем. Реализация будет происходить в activity. Аргумент этой функции – температура по Цельсию.
В функции onCreateView заполняем разметку, объявляем все элементы, к которым будем обращаться в коде.
Затем нужно обработать нажатие кнопок. Создаем функцию OnClick(View v). Получаем id нажатой кнопки, сравниваем его с id из R-файла. Если это кнопка выхода, то закрываем приложение. Поскольку из фрагмента нельзя вызвать функцию finish(), то получаем activity и с его помощью завершаем работу.
Если это кнопка расчета, то проверим, введена ли температура. Если нет, то выведем всплывающее сообщение и выйдем из функции. Если все нормально, то считываем значение температуры и преобразовываем его в значение типа Double.
Затем создаем объект интерфейса и присваиваем ему значение нашей главной активности. И уже этот объект (то есть активность) вызывает объявленную функцию.
Перейдем ко второму фрагменту. Создаем его так же, как и первый, называем fragment2.java. Здесь нам нужно будет выполнить расчет и вывести результат на экран.
Кроме того, надо учесть, что при повороте экрана активность (и фрагменты тоже) пересоздается, при этом уничтожаются значения в текстовых полях (TextView). Значения в EditText сохраняются, если поле имеет id. Поэтому будем сохранять эти значения в объект Bundle, а при создании фрагмента подставлять в нужные поля. Перед уничтожением активности вызывается функция onSaveInstanceState, вот в ней и будем сохранять значения.
Текст фрагмента:
package ru.studentshelper.fahrenheit1;

import ru.studentshelper.fahrenheit1.R;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class fragment2 extends Fragment {
    private TextView tvF;
    private TextView tvR;
    CharSequence sText;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        // return super.onCreateView(inflater, container, savedInstanceState);
        View viewHierarchy = inflater.inflate(R.layout.fragment2, container,
                false);
        tvF = (TextView) viewHierarchy.findViewById(R.id.tvF);
        tvR = (TextView) viewHierarchy.findViewById(R.id.tvR);
        if (savedInstanceState != null) {
            tvF.setText(savedInstanceState.getString("tvF"));
            tvR.setText(savedInstanceState.getString("tvR"));
        }
        return viewHierarchy;
    }

    void Calc(double tC) {
        tvR.setText(String.valueOf(5 * tC / 4));
        tvF.setText(String.valueOf(tC * 9 / 5 + 32));
    }

    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("tvF", tvF.getText().toString());
        outState.putString("tvR", tvR.getText().toString());
    }
}

Выполняет расчет и вывод результат на экран функция Calc.
Осталось скоординировать эти фрагменты между собой.
Перейдем к разметке activity_main:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorBack"
    android:orientation="vertical"
    tools:context="ru.studentshelper.fahrenheit1.MainActivity"
    tools:ignore="MergeRootFrame">
   
        <fragment
            android:id="@+id/fragment1"
            android:name="ru.studentshelper.fahrenheit1.fragment1"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            tools:layout="@layout/fragment1" />
       
        <fragment
            android:id="@+id/fragment2"
            android:name="ru.studentshelper.fahrenheit1.fragment2"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            tools:layout="@layout/fragment2" />

    </LinearLayout>
Результат:


Большую часть текста MainActivity уже создала среда разработки. Я не буду почти ничего менять, только добавлю кнопку меню «Выход». Еще нужна реализации функции из первого фрагмента. В этой функции (onBtnCalcClick) создается объект – менеджер фрагментов. Затем этот менеджер находит второй фрагмент по id, И, наконец, этот найденный фрагмент запускает функцию Calc.
Текст файла меню из папки menu (main.xml):
<menu 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"
    tools:context="ru.studentshelper.fahrenheit1.MainActivity" >

    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:title="@string/action_settings"
        app:showAsAction="never"/>
    <item
        android:id="@+id/exit_menu"
        android:orderInCategory="100"
        android:title="@string/menu_exit"
        app:showAsAction="never"/>

</menu>
Текст MainActivity.java:
package ru.studentshelper.fahrenheit1;

import ru.studentshelper.fahrenheit1.fragment1.OnbtnCalcClickListener;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends ActionBarActivity implements OnbtnCalcClickListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    public void onBtnCalcClick(double tCels) {
        // TODO Auto-generated method stub
        android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
        fragment2 f2 = (fragment2) fm.findFragmentById(R.id.fragment2);
        if (f2 != null)
            f2.Calc(tCels);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.exit_menu) {
            finish();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}
Да, не забывайте добавить implements OnbtnCalcClickListener к классу фрагмента.
Сейчас создадим папку layout-land, скопируем в нее файл activity_main.xml и изменим его (ориентация LinearLayout и параметры фрагментов):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorBack"
    android:orientation="horizontal"
    tools:context="ru.studentshelper.fahrenheit1.MainActivity"
    tools:ignore="MergeRootFrame" >
   
        <fragment
            android:id="@+id/fragment1"
            android:name="ru.studentshelper.fahrenheit1.fragment1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            tools:layout="@layout/fragment1" />
       
        <fragment
            android:id="@+id/fragment2"
            android:name="ru.studentshelper.fahrenheit1.fragment2"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            tools:layout="@layout/fragment2" />

    </LinearLayout>
Запускаем эмулятор и проверяем:

Программа для пересчета температуры на Android

Программа для пересчета температуры на Android