Урок 5. Створюємо вікно налаштувань.
Вікно налаштувань можна було б зробити аналогічно екрану “Про додаток”. Тоді довелося б самим писати код обробки кліків, збереження налаштувань і т.п. Але ми будемо використовувати спеціальний клас PreferenceActivity. Він сильно полегшує життя розробника при роботі з налаштуваннями програми.
Отже, створюємо новий клас PrefActivity так само як в уроці 4, але в рядку суперклас вказуємо PreferenceActivity. Створюємо метод onCreate:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
Тепер нам потрібно створити макет екрану налаштувань. Робиться він так: правою кнопкою натискаємо на папку res і створюємо нову папку з ім’ям “xml”. У цій папці ми створюємо Android XML File. У рядку Resource Type вибираємо Preference, кореневий елемент вказуємо PreferenceScreen. Задаємо ім’я файлу pref_screen.
Тепер нам потрібно описати елементи на екрані. Розмістимо на екрані чекбокс для включення додаткових кнопок і список для вибору стилю інтерфейсу калькулятора.
Для цього пишемо у pref_screen.xml:
<CheckBoxPreference
android: key = "add_button"
android: summary = "@ string / descr_add_bt"
android: title = "@ string / add_bt">
</ CheckBoxPreference>
<ListPreference
android: entries = "@ array / style_entries"
android: entryValues = "@ array / style_entry_values"
android: key = "style_calc"
android: summary = "@ string / descr_style_app"
android: title = "@ string / style_app">
</ ListPreference>
Розглянемо параметри: key – це ключ, ім’я по якому в коді ми будемо визначати стан налаштування, title – заголовок, який ми побачимо в полі налаштування, summary – текст-пояснення, розташований нижче заголовка. Для ListPreference є ще два параметри: entries – текст списку, який ми побачимо на екрані, entryValues - значення, які буде приймати key, при натисканні того чи іншого пункту списку. Зауважте всі параметри задаються строковими константами (із тих самих міркувань, що і раніше – з розрахунком на майбутню додаткову локазацію). Дивимося що нового додаємо у string.xml:
<string name="add_bt">Додаткові кнопки</string>
<string name="descr_add_bt">Відобразити додаткові кнопки</string>
<string name="style_app">Стиль програми</string>
<string name="descr_style_app">Зміни стиль интерфейса</string>
<string-array name="style_entries">
<item>Стиль 1</item>
<item>Стиль 2</item>
</string-array>
<string-array name="style_entry_values">
<item>1</item>
<item>2</item>
</string-array>
Зверніть увагу, як задаються масиви строкових констант.
Залишилося вказати PreferenceActivity який макет показати на екрані. Пишемо в onCreate:
addPreferencesFromResource (R.xml.pref_screen);
Вікно налаштувань готове. Переходимо в MainActivity.java і в обробнику натиснення на пункт меню “Налаштування” замінюємо вивід повідомлення на виклик activity:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.options_menu:
startActivity(new Intent(this, PrefActivity.class));
break;
Не забуваємо зареєструвати PreferenceActivity у маніфесті (робиться також як зі звичайним activity – див. Урок 4).
Запускаємо програму, викликаємо вікно налаштувань, натискаємо на пункти.
Наступним кроком нам потрібно отримати дані налаштувань в основний activity. Відкриваємо MainActivity.java. Оголошуємо об’єкт SharedPreferences і дві змінні для отримання налаштувань до onCreate:
SharedPreferences sp;
Boolean add_button;
String style_calc;
Для зручності імена змінних поставимо такі ж як у ключів в макеті налаштувань. У onCreate отримуємо SharedPreferences, яке працює з файлом налаштувань:
sp = PreferenceManager.getDefaultSharedPreferences (this);
Тепер нам потрібно додати метод onResume, який викликається системою, коли activity отримує фокус, тобто коли ми повертаємо його на екран. У ньому ми будемо отримувати настройки з SharedPreferences.
protected void onResume() {
add_button = sp.getBoolean("add_button", false);
style_calc = sp.getString("style_calc", "1");
super.onResume();
}
Налаштування отримані. Тепер їх потрібно якось застосувати. Стиль ми застосувати поки не можемо. Для цього ще потрібно багато зробити. Залишимо його в спокої до уроку, в якому робитимемо інтерфейс презентабельним. Займемося відображенням додаткових кнопок. Для початку їх потрібно додати на макет activity_main.xml. Додаємо горизонтальний layout і чотири кнопки в нього:
<LinearLayout
android:id="@+id/llExtra"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/btPoint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="." />
<Button
android:id="@+id/btSquare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="x*x" />
<Button
android:id="@+id/btRadical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="√" />
<Button
android:id="@+id/btBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="←" />
</LinearLayout>
Зверніть увагу, що layout теж отримав параметр id.
Повертаємося до MainActivity.java. Оголошуємо об’єкт LinearLayout, пов’язуємо його з layout’ом на макеті. У onResume додаємо код:
int flag_visiblity = View.INVISIBLE;
if(add_button)flag_visiblity = View.VISIBLE;
llExtra.setVisibility(flag_visiblity);
Оскільки метод setVisiblity вимагає на вхід параметр типу int, а ми отримуємо з налаштувань булеву змінну, довелося ввести проміжний прапор flag_visiblity і в залежності від значення add_button привласнювати йому те чи інше цілочисельне значення.
Запускаємо програму, тестуємо. Обробку натискань нових кнопок будемо кодувати в одному з наступних уроків. Цей урок закінчений.Програма сильно наповнилась кодом. Тому наведу лістинг тільки екрану налаштувань і MainActivity.java. З іншими файлами думаю розберетеся самі. У наступному уроці спробуємо трохи оптимізувати код – зменшити громіздкість і поліпшити читабельність.
pref_screen.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<CheckBoxPreference
android:key="add_button"
android:summary="@string/descr_add_bt"
android:title="@string/add_bt">
</CheckBoxPreference>
<ListPreference
android:entries="@array/style_entries"
android:entryValues="@array/style_entry_values"
android:key="style_calc"
android:summary="@string/descr_style_app"
android:title="@string/style_app">
</ListPreference>
</PreferenceScreen>
PrefActivity.java
package ru.urok.super_calc;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class PrefActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_screen);
}
}
MainActivity.java
package ru.urok.super_calc;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener {
// оголошуємо кнопки і текстове поле
Button btOne, btTwo, btThree, btFour, btFive;
Button btSix, btSeven, btEight, btNine, btZero;
Button btPlus, btMinus, btMulti, btDiv, btEqual, btClear;
TextView tvLCD;
// оголошуємо змінні для обчислень
int operand1, operand2, flagAction;
double result;
SharedPreferences sp;
Boolean add_button;
String style_calc;
LinearLayout llExtra;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sp = PreferenceManager.getDefaultSharedPreferences(this);
llExtra = (LinearLayout) findViewById(R.id.llExtra);
// зв'язуємо кнопки з макетом
btOne = (Button) findViewById(R.id.btOne);
btTwo = (Button) findViewById(R.id.btTwo);
btThree = (Button) findViewById(R.id.btThree);
btFour = (Button) findViewById(R.id.btFour);
btFive = (Button) findViewById(R.id.btFive);
btSix = (Button) findViewById(R.id.btSix);
btSeven = (Button) findViewById(R.id.btSeven);
btEight = (Button) findViewById(R.id.btEight);
btNine = (Button) findViewById(R.id.btNine);
btZero = (Button) findViewById(R.id.btZero);
btPlus = (Button) findViewById(R.id.btPlus);
btMinus = (Button) findViewById(R.id.btMinus);
btMulti = (Button) findViewById(R.id.btMulti);
btDiv = (Button) findViewById(R.id.btDiv);
btEqual = (Button) findViewById(R.id.btEqual);
btClear = (Button) findViewById(R.id.btClear);
tvLCD = (TextView) findViewById(R.id.tvLCD);
// призначаємо кнопкам слухача
btOne.setOnClickListener(this);
btTwo.setOnClickListener(this);
btThree.setOnClickListener(this);
btFour.setOnClickListener(this);
btFive.setOnClickListener(this);
btSix.setOnClickListener(this);
btSeven.setOnClickListener(this);
btEight.setOnClickListener(this);
btNine.setOnClickListener(this);
btZero.setOnClickListener(this);
btPlus.setOnClickListener(this);
btMinus.setOnClickListener(this);
btMulti.setOnClickListener(this);
btDiv.setOnClickListener(this);
btClear.setOnClickListener(this);
btEqual.setOnClickListener(this);
//оголошуємо змінні
operand1 = 0;
operand2 = 0;
result = 0;
flagAction = 0;
// Встановимо значення першого операнда в текстове поле
tvLCD.setText(Integer.toString(operand1));
}
protected void onResume() {
add_button = sp.getBoolean("add_button", false);
style_calc = sp.getString("style_calc", "1");
int flag_visiblity = View.INVISIBLE;
if(add_button)flag_visiblity = View.VISIBLE;
llExtra.setVisibility(flag_visiblity);
super.onResume();
}
@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) {
switch(item.getItemId()){
case R.id.options_menu:
startActivity(new Intent(this, PrefActivity.class));
break;
case R.id.about_menu:
startActivity(new Intent(this, AboutActivity.class));
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.btOne:
ClickNumber(1);
break;
case R.id.btTwo:
ClickNumber(2);
break;
case R.id.btThree:
ClickNumber(3);
break;
case R.id.btFour:
ClickNumber(4);
break;
case R.id.btFive:
ClickNumber(5);
break;
case R.id.btSix:
ClickNumber(6);
break;
case R.id.btSeven:
ClickNumber(7);
break;
case R.id.btEight:
ClickNumber(8);
break;
case R.id.btNine:
ClickNumber(9);
break;
case R.id.btZero:
ClickNumber(0);
break;
case R.id.btPlus:
if(flagAction == 0)flagAction = 1;
break;
case R.id.btMinus:
if(flagAction == 0)flagAction = 2;
break;
case R.id.btMulti:
if(flagAction == 0)flagAction = 3;
break;
case R.id.btDiv:
if(flagAction == 0)flagAction = 4;
break;
case R.id.btEqual:
switch(flagAction){
case 1:
result = operand1 + operand2;
break;
case 2:
result = operand1 - operand2;
break;
case 3:
result = operand1 * operand2;
break;
case 4:
result =(double) operand1 / (double) operand2;
break;
default:
Toast.makeText(this, "Операцію не задано", Toast.LENGTH_LONG);
}
if(flagAction != 0){
tvLCD.setText(Double.toString(result));
operand1 = 0;
operand2 = 0;
result = 0;
flagAction = 0;
}
break;
case R.id.btClear:
operand1 = 0;
operand2 = 0;
result = 0;
flagAction = 0;
tvLCD.setText(Integer.toString(operand1));
break;
}
}
private void ClickNumber(int num){
if(flagAction == 0){
operand1 = operand1*10 + num;
tvLCD.setText(Integer.toString(operand1));
}else{
operand2 = operand2*10 + num;
tvLCD.setText(Integer.toString(operand2));
}
}
}