reCode #4: Поля ввода
Впервые мы попробуем сделать что-то полезное. Сегодня мы познакомимся с полями ввода на примере урезанного калькулятора.
Создаем проект. Мой имеет такие параметры:
Application name: AddMul
Company Domain: recode
Package name: recode.addmul
Activity Name: MyActivity
Для начала нам нужно подготовить экран, то есть добавить кнопки, поля ввода и дать им соответствующие идентификаторы.
В верхних двух полях будем вводить два числа, а по нажатию кнопки они будут суммироваться или умножаться. В нижней части будем считать факториал числа. Результаты вычислений будут выводиться в текстовом поле сверху. Попытайтесь создать такой экран сами. Он никогда не будет лишним. Прошу сверить лишь id элементов:
[xml]
android:layout_height="fill_parent"
xmlns:android="/schemas.android.com/apk/res/android"
android:id="@+id/gridLayout">
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="0"
android:id="@+id/res"
android:layout_row="0"
android:layout_column="0"
android:layout_marginLeft="22dp"
android:textSize="50dp" />
android:layout_height="wrap_content"
android:inputType="number"
android:ems="10"
android:id="@+id/fNum"
android:layout_row="1"
android:layout_column="0"
android:layout_marginLeft="22dp" />
android:layout_height="wrap_content"
android:inputType="number"
android:ems="10"
android:id="@+id/sNum"
android:layout_row="1"
android:layout_column="1"
android:layout_marginLeft="22dp" />
android:layout_height="wrap_content"
android:inputType="number"
android:ems="10"
android:id="@+id/forFact"
android:layout_row="4"
android:layout_column="0"
android:layout_marginLeft="22dp"
android:layout_marginTop="70dp" />
[/xml]
Теперь приступим к работе с java-файлом. Когда я подготавливал материалы, то есть сам учился и делал то, что рассказываю сейчас вам, я столкнулся с некоторыми проблемами, которые не были лишними и позволили мне кое-что понять. О них попробую рассказать в процессе.
Проблема первая. Готовить материалы я начал в электричке, где доступа в интернет у меня не было. Android Studio при каждом запуске проекта качает так называемые gradle. Насколько я понял, это инструменты для сборки проекта. Если сети нет, то AS начинает ругаться и так и не собирает проект. Так как AS куда-то качает эти инструменты, то там они и хранятся. Чтобы собирать проекты офлайн, идем в настройки.
Там идем в пункт Gradle.
В пункте Project-level settings выбираем Use local gradle distribution и прописываем путь к папке gradle. У меня он выглядит так: /Users/glebnovikov/.gradle. Папка .gradle скрыта, вписать придется вручную. Когда вы снова будете иметь доступ к интернету, советую переключиться обратно.
В первую очередь надо присоединить все нужные библиотеки. Для того, чтобы не сильно заморачиваться, присоединим отдельные библиотеки целиком (отмечаются звездочкой):
[java]
import android.app.Activity;
import android.os.Bundle;
import android.view.*;
import android.view.View.*;
import android.widget.*;
[/java]
Сразу после открытия тела класса объявим элементы интерфейса:
[java]
TextView res;
Button add, mul, fact;
EditText fNum, sNum, forFact;
[/java]
Далее в методе onCreate найдем все эти элементы интерфейса:
[java]
res = (TextView) findViewById(R.id.res);
add = (Button) findViewById(R.id.add);
mul = (Button) findViewById(R.id.mul);
fact = (Button) findViewById(R.id.fact);
fNum = (EditText) findViewById(R.id.fNum);
sNum = (EditText) findViewById(R.id.sNum);
forFact = (EditText) findViewById(R.id.forFact);
[/java]
Теперь объявим обработчик, я его назвал action:
[java]
OnClickListener action = new OnClickListener() {
@Override
public void onClick(View v) {
}
};
[/java]
Приступим к самой важной детали — заполнению обработчика. Здесь я столкнулся с некоторыми проблемами, которые связаны с получением текста из полей ввода.
Проблема вторая: интуитивно я попробовал использовать то, что получил в поле ввода просто как строчку. У меня не было интернета и времени для развлечений было полно. Однако не тут то было… Какой тип данных имеет то, что мы вводим в поля ввода и отдаем приложению? Да, это тип, судя по коду, называется EditText,и с ним можно делать только то, что ему предначертано. Логично, не правда ли? Строчка, состоящая из содержимого поля ввода выглядит примерно так: fNum.getText().toString() — где перед первой точкой вписывается имя переменной, относящейся к объявленному полю ввода. У меня переменная и поле носят имя fNum.
Проблема третья: перед тем, как начать баловаться с вводом текста, я просто попытался выполнить какие-то действия с числовыми переменными и вернуть их значение, но приложение падало при каждом вызове действия. Как выяснилось позже, текстовому полю можно дать только строковое значение. Для того, чтобы вывести значение переменной, надо было написать вот это: textView.setText(«» + intVar) — где textView это идентификатор переменной, связанной с текстовым полем, а intVar какая-то числовая переменная, значение которой мы хотим вывести в текстовое поле.
Перед заполнением обработчика создадим простые алгебраические функции, которые мы будем вызывать внутри разработчика. Во избежание «каши» в коде создадим для этого отдельный java-файл. Я назвал его functions.java. Это имя понадобится нам для вызова методов класса из класса MyActivity.java. Останавливаться на содержании не стоит, ведь это простейшие алгебраические функции от двух и одного аргумента.
[java]
public class functions {
public static int add(int a, int b) { //считает сумму чисел a и b
return a+b;
}
public static int mul(int a, int b) { //считает произведение чисел a и b
return a*b;
}
public static int fact(int a) { //считает факториал числа a
if (a==0) { return 1; }
else { return a*(fact(a-1)); }
}
}
[/java]
Теперь, к примеру, функцию сложения можно будет вызвать из другого класса в той же папке таким образом: functions.add (<первое число>, <второе число>). Перейдем к заполнению обработчика. Опять же нам понадобится свитч по нажатой кнопке.
[java]
OnClickListener action = new OnClickListener() {
@Override
public void onClick(View v) {
int a, b; //далее нам понадобятся две переменные для сложения и умножения, объявим их перед свитчем
switch (v.getId()) { //на экране три кнопки, поэтому у свитча три случая для каждой кнопки
case R.id.add: //сложение
break;
case R.id.mul: //умножение
break;
case R.id.fact: //факториал
break;
}
}
};
[/java]
Покажу на примере сложения. Умножение выполняется аналогично, про факториал позже. Для начала надо определить не пустое ли поле, значение которого мы будем использовать. При выполнении алгебраических операций с пустыми полями приложение вылетит, проверял.
Как работает проверка? Берем переменную, ответственную за конкретное поле ввода («fNum»), получаем значение поля ввода на момент нажатия кнопки («fNum.getText()»), переводим значение в строчку («fNum.getText().toString()»), удаляем начальные и конечные пробелы в строке («fNum.getText().toString().trim()») и проверяем строку на пустоту встроенной функцией («fNum.getText().toString().trim().isEmpty()»). Поля у нас два, так что проверка должна быть для обоих, поэтому поставим оператор «или» между условиями для полей fNum и sNum:
[java]
if ((fNum.getText().toString().trim().isEmpty())||(sNum.getText().toString().trim().isEmpty())) {
res.setText("Error");
}
[/java]
По коду заметно, что в том случае, когда хотя бы одно из полей пустое, мы будем выводить слово «Error» в поле с результатом. Теперь перейдем к случаю, когда поля оказались непустыми. В этом случае в заведенные нами переменные запишем значения из полей ввода и в текстовом поле результата вернем значение нужной функции от двух аргументов:
[java]
if ((fNum.getText().toString().trim().isEmpty())||(sNum.getText().toString().trim().isEmpty())) {
res.setText("Error");
} else {
a = Integer.parseInt(fNum.getText().toString());
b = Integer.parseInt(sNum.getText().toString());
res.setText("" + functions.add(a, b));
}
[/java]
Случай с умножением выглядит почти идентично, только в конечном результате надо вернуть не результат сложения («functions.add(a, b)»), а результат умножения («functions.mul(a,b)» ). В случае с факториалом проверять придется только одно поле («forFact» ). Попробуйте написать код сами! После обработчика не забудьте дать всем кнопкам значение обработчика:
[java]
add.setOnClickListener(action);
mul.setOnClickListener(action);
fact.setOnClickListener(action);
[/java]
После всех манипуляций мой MyActivity.java выглядит так:
[java]
package recode.addmul;
import android.app.Activity;
import android.os.Bundle;
import android.view.*;
import android.view.View.*;
import android.widget.*;
public class MyActivity extends Activity {
TextView res;
Button add, mul, fact;
EditText fNum, sNum, forFact;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
res = (TextView) findViewById(R.id.res);
add = (Button) findViewById(R.id.add);
mul = (Button) findViewById(R.id.mul);
fact = (Button) findViewById(R.id.fact);
fNum = (EditText) findViewById(R.id.fNum);
sNum = (EditText) findViewById(R.id.sNum);
forFact = (EditText) findViewById(R.id.forFact);
OnClickListener action = new OnClickListener() {
@Override
public void onClick(View v) {
int a, b;
switch (v.getId()) {
case R.id.add:
if ((fNum.getText().toString().trim().isEmpty())||(sNum.getText().toString().trim().isEmpty())) {
res.setText("Error");
} else {
a = Integer.parseInt(fNum.getText().toString());
b = Integer.parseInt(sNum.getText().toString());
res.setText("" + functions.add(a, b));
}
break;
case R.id.mul:
if ((fNum.getText().toString().trim().isEmpty())||(sNum.getText().toString().trim().isEmpty())) {
res.setText("Error");
} else {
a = Integer.parseInt(fNum.getText().toString());
b = Integer.parseInt(sNum.getText().toString());
res.setText("" + functions.mul(a, b));
}
break;
case R.id.fact:
if (forFact.getText().toString().trim().isEmpty()) {
res.setText("Error");
} else {
a = Integer.parseInt(forFact.getText().toString());
res.setText("" + functions.fact(a));
}
break;
}
}
};
add.setOnClickListener(action);
mul.setOnClickListener(action);
fact.setOnClickListener(action);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.my, 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.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
[/java]
Теперь осталось запустить и протестировать. Дерзайте! По всем вопросам, как всегда, в комментарии на сайте, ко мне в твиттер или в личку в VK.
Комментариев 0
Авторизуйтесь через популярные соц.сети
Вконтакте Google+