1. С количеством ходов все понятно, будем считать количество открытых картинок и выводить это число в TextView. Для таймера есть класс Chronometer, который делает как раз то что нам нужно — отчитывает время. Класс унаследован от TextView, поэтому работать с ним можно как с обычным текстовым полем. Дополнительными являются методы:
void start () - запускает отсчет времени
void stop() - останавливает отсчет
void setFormat (String format) — устанавливает формат в котором будет выводится дата. По умолчанию форматом является MM:SS (или H:MM:SS). Можно задать свой формат, при этом в строке format первое встреченное «%s», будет заменено на «HH:MM». Например: «Time: %s» будет выводить время «Time: 01:30»
2. Добавим в main.xml TextView и Chronometr
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical" >
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/stepview"
- android:textSize="30dp"
- android:layout_weight="1"
- android:layout_marginLeft="10dip"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- />
- <Chronometer xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/timeview"
- android:layout_width="100dip"
- android:layout_height="wrap_content"
- android:textSize="30dp"
- />
- </LinearLayout>
- <GridView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/field"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- />
- </LinearLayout>
- public class MemoriaActivity extends Activity {
- ...
- private TextView mStepScreen;
- private Chronometer mTimeScreen;
- private Integer StepCount; // кол-во ходов
- @Override
- public void onCreate(Bundle savedInstanceState) {
- ...
- mTimeScreen = (Chronometer) findViewById(R.id.timeview);
- mStepScreen = (TextView)findViewById(R.id.stepview);
- // шрифт
- Typeface type = Typeface.createFromAsset(getAssets(),"my-font.ttf");
- mTimeScreen.setTypeface(type);
- mStepScreen.setTypeface(type);
- StepCount = 0;
- mStepScreen.setText (StepCount.toString());
- mTimeScreen.start();
- ...
- mGrid.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View v,int position, long id) {
- mAdapter.checkOpenCells ();
- mAdapter.openCell (position);
- StepCount ++;
- mStepScreen.setText (StepCount.toString());
- if (mAdapter.checkGameOver())
- {
- mTimeScreen.stop();
- String time = mTimeScreen.getText().toString();
- String TextToast = "Игра закончена nХодов: " + StepCount.toString() + "nВремя: " + time;
- Toast.makeText (getApplicationContext(), TextToast, Toast.LENGTH_SHORT).show();
- }
- }
- });
- }
- }
5. Тут, кстати, обнаружилась небольшая ошибка в игре: нажатие на уже удаленную картинку считается ходом, что не правильно. Переделаем метод openCell() в классе GridAdapter, он должен проверять является ли карточка закрытой и только тогда ее открывать.
- public boolean openCell(int position) {
- if (arrStatus.get(position) == Status.CELL_DELETE || arrStatus.get(position) == Status.CELL_OPEN)
- return false;
- if (arrStatus.get(position) != Status.CELL_DELETE)
- arrStatus.set(position, Status.CELL_OPEN);
- notifyDataSetChanged();
- return true;
- }
- mGrid.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View v,int position, long id) {
- mAdapter.checkOpenCells ();
- if (mAdapter.openCell (position)) {
- StepCount ++;
- mStepScreen.setText (StepCount.toString());
- }
- ...
- }
- });
Typeface type = Typeface.createFromAsset(getAssets(),"my-font.ttf");
mTimeScreen.setTypeface(type);
Таким способом можно установить свой шрифт для TextView. Берем файл шрифта (у меня это 'my-font.ttf'), кладем его в директорию /assets.
Typeface — класс стилей шрифта.
createFromAsset(AssetManager mgr, String path) — создает экземпляр класса Typeface, используя файл из директории /assets.
setTypeface(Typeface) — устанавливает шрифт в TextView.
7. В xml и у TextView и у Chronometer также описаны параметры шрифта
android:textSize="30dp"
android:textColor="#FFFFFF"
Две строчки, конечно, можно и скопировать в два места, но если или строчек или мест будет много, то это неудобно, да и места много занимает. Создадим стиль шрифта. Добавим файл style.xml в директорию /res/values/. Напишем туда:
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <style name="MyText">
- <item name="android:textColor">#FFFFFF</item>
- <item name="android:textSize">30dp</item>
- </style>
- </resources>
style="@style/MyText"
Теперь чтобы изменить стиль шрифта и в TextView и в Chronometer, надо изменить только файл style.xml, например добавим тень к тексту:
- <style name="MyText">
- <item name="android:textColor">#FFFFFF</item>
- <item name="android:textSize">30dp</item>
- <item name="android:shadowColor">#FF0000</item>
- <item name="android:shadowDx">2</item>
- <item name="android:shadowDy">2</item>
- <item name="android:shadowRadius">3</item>
- </style>
- Первое запретить поворот зкрана, сам-то телефон конечно крутить можно, но изображение от этого меняться не будет. Для этого добавим строку android:screenOrientation="portrait" в файл AndroidManifest.xml:
- <activity
- android:name=".MemoriaActivity"
- android:label="@string/app_name"
- android:screenOrientation="portrait">
- И наконец третий способ, отловить поворот экрана программно, для этого добавим в AndroidManifest.xml за каким изменением конфигурации мы хотим следить
- <activity
- android:name=".MemoriaActivity"
- android:label="@string/app_name"
- android:configChanges="orientation">
- public class MemoriaActivity extends Activity {
- ...
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
- mGrid.setNumColumns(9);
- if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
- mGrid.setNumColumns(6);
- }
- }
9. Теперь сделаем начальный экран, у меня это будет четыре кнопки (Старт, Настройки, Рекорды, Выход) на каком-нибудь фоне. Создаем файл MemoriaStart.java с классом MemoriaStart (унаследованным от Activity) и разметку start.xml. Я сделаю две разметки для вертикальной и горизонтальной ориентации.
10. Если после этого запустить программу, то откроется окно MemoriaActivity, для того чтобы первым открывалось MemoriaStart изменим AndroidManifest.xml:
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name" >
- <activity
- android:name=".MemoriaStart"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name=".MemoriaActivity"
- android:label="@string/app_name"
- android:configChanges="orientation">
- </activity>
- </application>
- public class MemoriaStart extends Activity {
- Button mStart;
- Button mExit;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.start);
- mStart = (Button)findViewById(R.id.butStart);
- mExit = (Button)findViewById(R.id.butExit);
- mStart.setOnClickListener (new OnClickListener() {
- @Override
- public void onClick(View v) {
- startGame();
- }
- });
- mExit.setOnClickListener (new OnClickListener() {
- @Override
- public void onClick(View v) {
- finish();
- }
- });
- }
- private void startGame () {
- Intent i = new Intent(this, MemoriaActivity.class);
- startActivity (i);
- }
- }
Intent (намерение) — структура данных, содержащая информацию о том, какое действие необходимо выполнить. В данном случае, мы вызываем окно MemoriaActivity.
12. Запускаем, теперь при запуске программы, вначале показывается окно с кнопками, при нажатии на «Старт» запускается игра, а кнопка «Выход» закрывает приложение. Чтобы из игры вернуться на начальный экран можно нажать кнопку «Назад» на телефоне, но для наглядности после завершения игры будем показывать не просто всплывающее сообщение, а диалоговое окно с кнопкой, по нажатию на которое будем возвращаться назад.
В классе MemoriaActivity при завершении игры вызовем функцию ShowGameOver()
- public class MemoriaActivity extends Activity {
- ...
- mGrid.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View v,int position, long id) {
- ...
- if (mAdapter.checkGameOver())
- {
- mTimeScreen.stop();
- ShowGameOver();
- }
- }
- });
- }
- public class MemoriaActivity extends Activity {
- ...
- private void ShowGameOver () {
- // Диалоговое окно
- AlertDialog.Builder alertbox = new AlertDialog.Builder(this);
- // Заголовок и текст
- alertbox.setTitle("Поздравляем!");
- String time = mTimeScreen.getText().toString();
- String TextToast = "Игра закончена nХодов: " + StepCount.toString() + "nВремя: " + time;
- alertbox.setMessage(TextToast);
- // Добавляем кнопку
- alertbox.setNeutralButton("Ok", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface arg0, int arg1) {
- // закрываем текущюю Activity
- finish();
- }
- });
- // показываем окно
- alertbox.show();
- }
- }
AlertDialog.Builder — вспомогательный класс, который создает диалоговое окошко.
Методы setTitle(CharSequence title) и setMessage(CharSequence message) задают соответственно заголовок и текст сообщения.
setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) — создает в окне кнопку и устанавливает обработчик нажатия на кнопку.
show() - создает и показывает созданное окно.
13. Запускаем, все работает. Мы сделали счетчики, и начальный экран. Попутно посмотрели как установить свой шрифт, как сделать общий стиль для нескольких элементов приложения, как реагировать на изменения ориентации экрана и научились выводить диалоговое окошко.
Исходники:
Memoria-2.zip
Все части урока:
1. Игровое поле 6х6 с картинками (часть 1)
2. Учет количество ходов (или времени) (часть 2)
3. Просмотр таблицы рекордов (часть 4)
4. Настройки: выбор цвета фона и набора картинок (часть 3)
5. Начальный экран (Часть 2)
Счетчик ходов работает некорректно, одно нажатие выдает за 2 и еще при нажатии на пустое поле тоже засчитываеь как ход, или нажатие на открытую картинку...
ОтветитьУдалить