Програмуємо калькулятор на андроїд. Урок 5

Урок 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));
   }
 }
}