ViewPagerを使用してスライドする画面を作成してみる

Androidでスワイプすると左右にページが変わるページを作りたい。とういうことで調べてみた。ViewPagerというものがあった。

1.作成するファイル

プログラム

  • MainActivity.java
  • ViewPagerAdapter.java
  • LeftViewFragment.java
  • CenterViewFragment.java
  • RightViewFragment.java

レイアウト

  • activity_main.xml
  • left_view_fragment.xml
  • center_view_fragment.xml
  • right_view_fragment.xml

2.画面

こんな感じ

ViewPager

スワイプすると画面がスライドして変わる。

3.画面のFragment

LeftViewFragment.javaのソース

import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class LeftViewFragment extends Fragment {
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		View view = inflater.inflate(R.layout.left_view_fragment, null);
	    return view;
	}
}

left_view_fragment.xml

<?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:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="Left Fragment" />

</LinearLayout>

同様に、センター用Fragmentとライト用Fragmentを作成する。

4.Fragmentを管理するadapterを作成

作成した3つのFragmentを管理するadapterを作成する。

import jp.dangoya.android.viewpagersample.LeftViewFragment;
import jp.dangoya.android.viewpagersample.CenterViewFragment;
import jp.dangoya.android.viewpagersample.RightViewFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;

public class ViewPagerAdapter extends FragmentStatePagerAdapter {
	public ViewPagerAdapter(FragmentManager fm) {
		super(fm);
	}

	@Override
	public Fragment getItem(int position) {
		switch (position) {
	    case 0:
	    	return new LeftViewFragment();
	    case 1:
	    	return new CenterViewFragment();
	    default:
	    	return new RightViewFragment();
	    }
	}

	// ページ数
	@Override
	public int getCount() {
		return 3;
	}

	// タブタイトル
	@Override
	public CharSequence getPageTitle(int position) {
		switch (position) {
		case 0:
			return "Left View";
		case 1:
			return "Center View";
		case 2:
			return "Right View";
		}
		return "";
	}
}

5.メイン画面

メインのActivity
MainActivity.java

import jp.dangoya.android.viewpagersample.ViewPagerAdapter;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;

public class MainActivity extends FragmentActivity {
	ViewPager viewPager;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		viewPager = (ViewPager) findViewById(R.id.pager);
		viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager()));
	}
}

メインのレイアウト
activity_main.xml

<android.support.v4.view.ViewPager
  	xmlns:android="http://schemas.android.com/apk/res/android"
  	android:id="@+id/pager"
  	android:layout_width="match_parent"
  	android:layout_height="match_parent">

  	<android.support.v4.view.PagerTitleStrip
	    android:layout_width="match_parent"
	    android:layout_height="wrap_content"
	    android:layout_gravity="top"
	    android:background="#CCCCCC"
	    android:textColor="#000000"
	    android:paddingTop="10dp"
	    android:paddingBottom="10dp"/>

</android.support.v4.view.ViewPager>

ソース
ViewPagerSample

2013年12月29日 | カテゴリー : Android | 投稿者 : mitarashidango

C#からSQLiteのDBを操作する

SQLiteのDBを操作するGUIを作成したい。ということで調べてみた。
System.Data.SQLite.dllとVisual Studio Express 2013 for Windows DesktopのC#を使用して作成してみた。
環境は「Windows 7 32bit」と「.NET Framework 4.5」

1.「System.Data.SQLite.dll」のダウンロード

System.Data.SQLite.dllをサイトからダウンロード、対象の.NET Frameworkのものをダウンロード、ここでは4.5なので4.5のものをダウンロード。インストール版とバイナリ版があるが、バイナリ版をダウンロードする。2種類あったけど、たぶんどっちでもいいと思う。

image029

2.Visual Studioで参照設定する。

「ソリューションエクスプローラ」から「参照設定」からSystem.Data.SQLite.dllを追加する。

image021

image024

3.SQLiteのDBファイルを用意する

ファイル名を「sample.db」とし以下テーブル作成のSQL

CREATE TABLE Sample (
	Id INTEGER PRIMARY KEY AUTOINCREMENT,
	Name TEXT,
	Age INTEGER
)

4.C#でプログラムを作成

SQLiteと接続するために「using System.Data.SQLite;」の文を忘れずに書く。
接続、追加、取得だけの以下のもの作成。

image025

以下ソース

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data.SQLite;
using System.Diagnostics;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        // データ接続
        private void button1_Click(object sender, EventArgs e) {
            string dbConnectionString = "Data Source=E:\\sample.db";
            using (SQLiteConnection cn = new SQLiteConnection(dbConnectionString)) {
                try {
                    cn.Open();
                    MessageBox.Show("接続できました。", "タイトル", MessageBoxButtons.OK, MessageBoxIcon.Information);
                } catch (Exception exception) {
                    MessageBox.Show(exception.Message, "タイトル", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        // データの追加
        private void button3_Click(object sender, EventArgs e) {
            string dbConnectionString = "Data Source=E:\\sample.db";
            using (SQLiteConnection cn = new SQLiteConnection(dbConnectionString)) {
                cn.Open();
                using (SQLiteTransaction trans = cn.BeginTransaction()) {
                    SQLiteCommand cmd = cn.CreateCommand();

                    // インサート文
                    cmd.CommandText = "INSERT INTO Sample (Name, Age) VALUES (@Name, @Age)";

                    // パラメータのセット
                    cmd.Parameters.Add("Name", System.Data.DbType.String);
                    cmd.Parameters.Add("Age", System.Data.DbType.Int64);

                    // データの追加
                    cmd.Parameters["Name"].Value = "田中";
                    cmd.Parameters["Age"].Value = 25;
                    cmd.ExecuteNonQuery();

                    cmd.Parameters["Name"].Value = "高橋";
                    cmd.Parameters["Age"].Value = 30;
                    cmd.ExecuteNonQuery();

                    // コミット
                    trans.Commit();
                }
            }
        }

        // データの取得
        private void button4_Click(object sender, EventArgs e) {
            string dbConnectionString = "Data Source=E:\\sample.db";
            using (SQLiteConnection cn = new SQLiteConnection(dbConnectionString)) {
                cn.Open();
                SQLiteCommand cmd = cn.CreateCommand();
                cmd.CommandText = "SELECT * FROM Sample";
                using (SQLiteDataReader reader = cmd.ExecuteReader()) {
                    while (reader.Read()) {
                        Debug.WriteLine("名前:" + reader["Name"].ToString());
                        Debug.WriteLine("年齢:" + reader["Age"].ToString());
                    }
                }
                cn.Close();
            }
        }
    }
}

5.実行

「SQLiteに接続」をクリックすると接続完了のメッセージを出力
「データ追加」とクリックするとSampleテーブルにデータを追加する
「データ取得」をクリックして追加されたデータを確認

image001

ListFragmentを使用してリストを作ってみる

今までリストを使用するときは、ListActivityを使用してたんだけど、
ListFragmentを覚えた方がいいと思ってListFragmentの簡単なサンプルを作成してみた。
サンプルはリストをListFragmentを使用して作成。リストの項目は自分で作成したレイアウトを使用(ここではテキストとボタンのみのシンプルなもの)

1.作成するファイル

  • MainActivity.java
  • MyListFragment.java
  • activity_main.xml
  • my_listfragment_row.xml

2.MainActivity.java

特に修正なし、プロジェクト作成で作成されたものそのまま

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

	@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;
	}

}

3.MyListFragment.java

これでListFragmentを使用したリストを作成する。リスト用のadapterは自分で作成する。
リスト用のレイアウトに「my_listfragment.xml」、リストの項目用に「my_listfragment_row.xml」を使用。
動作としてはリスト項目のテキストを動的に作成、ボタンはクリックしたときにリストのテキストをToastで表示。

import java.util.ArrayList;
import java.util.List;
import android.app.ListFragment;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MyListFragment extends ListFragment {
	private List<ListItem> list;
	private ArrayAdapter<ListItem> adapter;

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);

		list = new ArrayList<ListItem>();
		list.add(new ListItem("リスト1"));
		list.add(new ListItem("リスト2"));
		list.add(new ListItem("リスト3"));
		list.add(new ListItem("リスト4"));
		list.add(new ListItem("リスト5"));
		list.add(new ListItem("リスト6"));
		list.add(new ListItem("リスト7"));
		list.add(new ListItem("リスト8"));
		list.add(new ListItem("リスト9"));
		list.add(new ListItem("リスト10"));
		list.add(new ListItem("リスト11"));
		list.add(new ListItem("リスト12"));
		list.add(new ListItem("リスト13"));
		list.add(new ListItem("リスト14"));
		list.add(new ListItem("リスト15"));
		list.add(new ListItem("リスト16"));
		list.add(new ListItem("リスト17"));
		list.add(new ListItem("リスト18"));
		list.add(new ListItem("リスト19"));
		list.add(new ListItem("リスト20"));

		adapter = new ListAdapter(getActivity(), list);
		setListAdapter(adapter);
	}

	private class ListAdapter extends ArrayAdapter<ListItem> {
		private LayoutInflater mInflater;

		public ListAdapter(Context context, List<ListItem> objects) {
			super(context, 0, objects);
			mInflater = (LayoutInflater)context
					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		}

		public View getView(int position, View convertView, ViewGroup parent) {
			final ViewHolder holder;
			if (convertView == null) {
				convertView = mInflater.inflate(R.layout.my_listfragment_row, parent, false);
				holder = new ViewHolder();
				holder.tvListText = (TextView)convertView.findViewById(R.id.list_text);
				holder.btListButton = (Button)convertView.findViewById(R.id.list_button);
				convertView.setTag(holder);
			} else {
				holder = (ViewHolder)convertView.getTag();
			}
			final ListItem item = getItem(position);
			holder.tvListText.setText(item.getListText());
			holder.btListButton.setOnClickListener(new OnClickListener() {
	        	public void onClick(View v) {
	        		Toast.makeText(getActivity(),
	        				item.getListText(), Toast.LENGTH_SHORT).show();
	        	}
	        });

			return convertView;
		}
	}

	private class ListItem {
		private String listText = "";

		public ListItem() {
		}

		public ListItem(String listText) {
			this.listText = listText;
		}

		public void setListText(String listText) {
			this.listText = listText;
		}

		public String getListText() {
			return this.listText;
		}
	}

	private class ViewHolder {
		TextView tvListText;
		Button btListButton;
	}
}

4.activity_main.xml

メインのレイアウト。ここではListFragmentのみ表示。

<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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <fragment
		android:name="jp.dangoya.android.listfragmentsample.MyListFragment"
      	android:id="@+id/fragment1"
      	android:layout_width="match_parent"
      	android:layout_height="0dp"
      	android:layout_weight="1" />

</LinearLayout>

5.my_listfragment_row.xml

リストの項目用レイアウト。ここではテキストと、ボタンをセット

<?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="horizontal" >"

    <TextView
        android:id="@+id/list_text"
        android:padding="10dp"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text=""
        android:layout_weight="1"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <Button
        android:id="@+id/list_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="10dp"
        android:text="ボタン" />

</LinearLayout>

6.実行

実行するとこんな感じ。ソースは下にリンクしてます。
image002

ListFragmentSample

EclipseのAndroidプロジェクトをEclipseを使用しないでビルドする

Androidアプリをチームで開発を行っているんだけど、複数端末でビルドしたい。その際Eclipseを起動したくない。
ということで調べてみた。Gradleというもので実現できた。

1.Java、AndroidSDKのセット

Androidの開発環境設定ができているならば、もう設定済みだと思うが、一応

[環境変数のセット]
JAVA_HOME
ANDROID_HOME

[パスのセット]
%JAVA_HOME%\bin
%ANDROID_HOME\platform-tools

AndroidSDKで「Android SDK Build Tools」が必要なのでチェックしておく

image005

2.Gradleのインストール

Gradleのインストール。インストールといってもGradleサイトから持ってきたものを解凍するだけ
ここでは1.6を使用。(1.9でビルドしようとしたらだめだった)

[環境変数のセット]
GRADLE_HOME

[Gradleのパスのセット]
%GRADLE_HOME%\bin

3.EclipseでGradleファイルのエクスポート

Eclipseのプロジェクト上でGradleのビルド用ファイルを作成する。
image011

「Generate Gradle build files」を選択し、次へ
image015

プロジェクトフォルダ内に以下のフォルダと、ファイルが作成される。
image021

4.ビルド

プロジェクトフォルダ内に作成された「gradlew.bat」を実行
image023

「BUILD SUCCESSFUL」とでてビルドの成功

5.apkファイルの作成

これだけだとまだapkファイルは作成されないので、apkファイルを作成する。
コマンドラインプロンプトから「gradle assemble」と入力
image025

いろいろと注意メッセージが出たけど、一応成功
プロジェクトフォルダ内直下に「.gradle」と「build」というフォルダが作成されて、「build\apk」フォルダにapkファイルが作成される。
image030

署名付きのapkファイルを作成するには別途設定がいると思うんだけど、これはテスト環境なのでこれで終了

6.実機にインストール

adb install [apkファイルパス]
image032

とりあえず動いた。

JavaScriptで15パズル

JavaScriptで15パズルを作成してみた。
ゲームライブラリとして使用したのはenchant.js
画像は適当に作った。

15パズル

各種宣言

enchant();
var BOARD_WIDTH = 547;
var BOARD_HEIGHT = 547;
var PIECE_HEIGHT = 128;
var PIECE_WIDTH = 128;
var BOARD_START_X = 28;
var BOARD_START_Y = 28;
var PIECE_MOVE_VALUE_X = 122;
var PIECE_MOVE_VALUE_Y = 122;
var DEFAULT_FONT = "";
var imageSets = [
				"images/board.png",
				"images/piece1.png",
				"images/piece2.png",
				"images/piece3.png",
				"images/piece4.png",
				"images/piece5.png",
				"images/piece6.png",
				"images/piece7.png",
				"images/piece8.png",
				"images/piece9.png",
				"images/piece10.png",
				"images/piece11.png",
				"images/piece12.png",
				"images/piece13.png",
				"images/piece14.png",
				"images/piece15.png"
			];
var core = null;
var rootScene = null;
var pieces = new Array(15);
var spacePosition = 16;				// 空いているポジション
var pieceMoving = false;			// ピースが移動中か判別
var gameFinishFlag = true;			// ゲーム終了フラグ
var startTime = null;				// スタートタイム
var movingCount = 0;				// 動かしたカウント

フレーム更新時の処理

メインの処理。「rootScene.addEventListener(“enterframe”, function() {})」
1秒間に指定回数このイベントが走る(デフォルト30)。ここではラベルの表示、クリア判定を行っている。

rootScene.addEventListener("enterframe", function() {
	// タイム
	if (startTime != null) {
		nowTime = (new Date()).getTime();
		time = Math.floor((nowTime - startTime) / 1000);
		timeLabel.text = "タイム:" + time;
	}

	// 手数カウント
	movingCountLabel.text = "手数:" + movingCount;

	// クリア判定
	if (gameFinishFlag == false) {
		if (pieceMoving == false) {
			if (isClear()) {
				if (confirm("クリア!。もう一度やりますか?") == true) {
					deletePieces();
					startGame();
				} else {
					gameFinishFlag = true;
				}
			}
		}
	}
});

ピースクラス

ピースクラス、enchant.jsのSpriteクラスを継承して、移動時の処理などをしている。

var Piece = Class.create(Sprite, {
	initialize: function(image, number, position) {
		Sprite.call(this, PIECE_HEIGHT, PIECE_WIDTH);
		this.number = number;
		this.position = position;
		this.image = core.assets[image];
		this.start_x = 0;
		this.start_y = 0;
	},
	ontouchstart: function(e) {
		this.start_x = e.x;
		this.start_y = e.y;
	},
	ontouchend: function(e) {
		// 他のピースが移動中なら終了
		if (pieceMoving == true) {
			return;
		}

		// 距離取得
		var up = Math.floor(this.start_y - e.y);
		var down = Math.floor(e.y - this.start_y);
		var left = Math.floor(this.start_x - e.x);
		var right = Math.floor(e.x - this.start_x);

		// 最大値取得
		var max = Math.max(Math.max(Math.max(up, down), left), right);

		// 移動
		switch (max) {
		case up:
			// 上
			if (this.position - 4 != spacePosition) {
				break;
			}
			pieceMoving = true;
			this.tl.moveBy(0, -PIECE_MOVE_VALUE_Y, 5);
			this.tl.delay(5).then(function() {pieceMoving = false;});
			spacePosition = this.position;
			this.position = this.position - 4;
			movingCount++;
			break;
		case down:
			// 下
			if (this.position + 4 != spacePosition) {
				break;
			}
			pieceMoving = true;
			this.tl.moveBy(0, PIECE_MOVE_VALUE_Y, 5);
			this.tl.delay(5).then(function() {pieceMoving = false;});
			spacePosition = this.position;
			this.position = this.position + 4;
			movingCount++;
			break;
		case left:
			// 左
			if (this.position - 1 != spacePosition) {
				break;
			}
			pieceMoving = true;
			this.tl.moveBy(-PIECE_MOVE_VALUE_X, 0, 5);
			this.tl.delay(5).then(function() {pieceMoving = false;});
			spacePosition = this.position;
			this.position = this.position - 1;
			movingCount++;
			break;
		case right:
			// 右
			if (this.position + 1 != spacePosition) {
				break;
			}
			pieceMoving = true;
			this.tl.moveBy(PIECE_MOVE_VALUE_X, 0, 5);
			this.tl.delay(5).then(function() {pieceMoving = false;});
			spacePosition = this.position;
			this.position = this.position + 1;
			movingCount++;
			break;
		default:
		}
	},
	remove: function() {
		rootScene.removeChild(this);
		delete this;
	},
	isCorrectPosition: function() {
		return this.position == this.number;
	}
});

不可能問題

15パズルには絶対に解けない配置があって下図の形になる。最後の14と15が交換できない。
名称未設定
これを回避するにはシャッフルしたときに、解くのが不可能な配置かどうか判別する必要がある。
以下が判別するためのコード。詳細は省略するけどこの関数で判別できる。

function isPossiblePuzzle(ary) {
	var aryTmp = new Array(ary[0], ary[1], ary[2], ary[3],
						ary[4], ary[5], ary[6], ary[7],
						ary[8], ary[9], ary[10], ary[11],
						ary[12], ary[13], ary[14], ary[15]
						);
	var tmp = 0;
	var changingCount = 0;

	// 数値交換回数を求める
	for (var i = 0; i < aryTmp.length - 1; i++) {
		for (var j = i + 1; j < aryTmp.length; j++) {
			if (i + 1 == aryTmp[j]) {
				tmp = aryTmp[i];
				aryTmp[i] = aryTmp[j];
				aryTmp[j] = tmp;
				changingCount++;
				break;
			}
		}
	}

	// 交換回数が偶数なら解ける、奇数なら解けない
	if (changingCount % 2 == 0) {
		return true;
	} else {
		return false;
	}
}

プログラム

作成したプログラムはGitHubに置いてあります。