【Android】プリファレンスを利用してデータを簡単に保存する

Androidアプリ開発で、データを保存する方法はいくつかある。

データを保存・利用するには「SQLite」などのデータベースを使用するのが一般的であるが、データベースを使うまでもない事もある。 そういった場合、Androidでは「プリファレンス」というキー名と値の組合わせから構成されるデータをXML形式で保存する機能がある。

保存できるデータは、boolean型、float型、int型、long型、String型のみ。

今回は、このプリファレンスを利用してデータを簡単に保存し、出力してみる。

【値を保存】

// オブジェクトを取得 getSharedPreferences("プリファレンス名", 共有モード);
SharedPreferences pref_in = getSharedPreferences("prefname", MODE_PRIVATE);
// エディターオブジェクト生成
Editor editor = pref_in.edit();
// プリファレンスファイルへの書き込み putString("キー名", "データ")
editor.putString("keyname", "data");
// commit()メソッドの実行で値を保存
editor.commit();

【保存データを取得】

// オブジェクトを取得 getSharedPreferences("プリファレンス名", 共有モード);
SharedPreferences pref_out = getSharedPreferences("prefname", MODE_PRIVATE);
// プリファレンスファイルからデータを取得 putString("キー名", "データ")
String str = pref_out.getString("keyname", "data");

【利用例】

public class Activity000 extends Activity {
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		// 値を保存
		SharedPreferences pref_in = getSharedPreferences("name", MODE_PRIVATE);
		Editor editor = pref_in.edit();
		editor.putString("key1", "001");
		editor.putString("key2", "あいうえお");
		editor.commit();
		
		// 保存データを取得
		SharedPreferences pref_out = getSharedPreferences("name", MODE_PRIVATE);
		String str1 = pref_out.getString("key1", "default");
		String str2 = pref_out.getString("key2", "default");
		
		// データを出力
		Toast.makeText(getBaseContext(), str1, Toast.LENGTH_SHORT).show();
		Toast.makeText(getBaseContext(), str2, Toast.LENGTH_SHORT).show();
	}
}

【出力結果】

Preferences

【Android】カスタムViewから起動させるActivityに値を渡す方法

SurfaceviewなどのカスタムViewから起動させるActivityに値を渡したい。

当然、通常のActivityから起動する時と同じ記述ではうまくいかない。
カスタムViewからコンテキスト(Context)というのを利用するらしい。

コンテキスト(Context)とは:アプリケーションの情報をグローバルに受け渡しする為のインターフェース

Intent intent = new Intent(getContext(), ActivityNext.class);
intent.putExtra("key", key);
getContext().startActivity(intent);

intent.putExtra(Keyの名前, 渡す値);

【HTML/CSS】ヘッダーをページ上部に固定してレイアウトする

ヘッダー部分をスクロールしてもページ上部に固定されたままコンテンツ部分のみスクロールするようにレイアウトする。

今回の仕様は、ヘッダー部分をポジションで固定(絶対位置に配置)して、ヘッダーの高さ分だけ、コンテンツ上部にマージンを持たせる事で実現する。

【test.html】
<!DOCTYPE HTML>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>header固定テスト</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/test.css">

<!--[if IE]>
<script type="text/javascript">
	document.createElement('header');
	document.createElement('section');
	document.createElement('nav');
	document.createElement('footer');
</script>
<![endif]-->  
	
</head>
<body>

<header>
	<section id="header">
		<h1>タイトル/header固定テスト</h1>
		<nav></nav>
	</section>
</header>

<div id="contents">
コンテンツ<br />
コンテンツコンテンツ<br />
コンテンツコンテンツコンテンツ<br />
コンテンツコンテンツコンテンツコンテンツ<br />
コンテンツコンテンツコンテンツコンテンツコンテンツ<br />
	・
	・
	・
	・
	・
コンテンツコンテンツ<br />
コンテンツコンテンツコンテンツ<br />
コンテンツコンテンツコンテンツコンテンツ<br />
コンテンツコンテンツコンテンツコンテンツコンテンツ<br />
</div>

<footer>
	<p>footer</p>
</footer>

</body>
</html>
【css/test.css】
body{  
    padding-top: 100px;
	background: #CCCCCC;
}  

header{
	position: fixed !important;  
	position: absolute;  
	top: 0;  
	left: 0;
	width: 100%;
	height: 100px;
	margin: 0 auto;
	background: #000000;
}

header section#header{
	width: 1000px;
	margin: 0 auto;
}

header section#header h1{
	color: #FFFFFF;
}

#contents{
	width: 1000px;
	margin: 0 auto;
	border: 1px solid #333333;
	background: #FFFFFF;
}

footer{
	width: 1000px;
	height: 80px;
	margin: 0 auto;
	background: #000000;
	color: #FFFFFF;
	text-align: center;
}

position: fixed;は絶対位置への配置、スクロールしても位置を固定する。

【出力結果】

ヘッダーをページ上部に固定する

【PHP】GETで送信する文字列に”.”(ドット)が含まれる場合の対策

$_GETで送信する文字列に”.”(ドット)が含まれる場合、PHP は“.”(ドット)“_”(アンダースコア)に自動的に変換します。
その為、GETメソッドで値を受け取ろうとすると文字列が”_”(アンダースコア)に変換されたまま受け取る事になる。
例)
ore-memo.com

ore-memo_com

php.iniファイルのregister_globalsをoffにするなどの対応もできますが、php.iniファイルや.htaccessファイルはいつでも変更できるわけではないので、PHPファイル内で対応してみた。

【解決方法】
サーバ変数、
$_SERVER['QUERY_STRING']
で取得できるデータから、欲しい文字列を抜き取る方法で解決できた。

例)
http://www.ore-memo.com/index.html?url=ore-memo.com
の場合、

	// サーバ変数の中身をexplodeで分割し配列に入れる
	$get_data = explode("=", $_SERVER['QUERY_STRING']);
	
	// 特殊文字を元に戻す
	echo urldecode($get_data[0])."<br />";
	echo urldecode($get_data[1]);

サーバ変数$_SERVER['QUERY_STRING']の中には”?”以降の文字列が入る為、”=”で分割して値を取り出す必要がある。

【出力結果】
url
ore-memo.com

GETメソッドで複数の値を受け取る場合は、”&”で分割したのち、”=”で再度分割する。

【Android】画像を画面サイズに合わせて表示する(マルチデバイス対応)

画像を複数デバイスの画面サイズに合わせて表示しマルチデバイスに対応したい。

Androidデバイスは画面サイズやアスペクト比がさまざまで、基準が決めにくい為、
iphone3G(320×480px)やiphone4(640×960px)の画像解像度のアスペクト比2:3を基準にする。

■仕様■
・準備する画像はすべてアスペクト比2:3とする。
・画面表示は横幅を基準とし、横幅いっぱいに表示する。
・ほとんどの機種で高さが少し短くなるので、画像を中央に配置し、余白(背景)は黒にする。
・現行機種でアスペクト比2:3よりも高さが小さいものはない様なので、このタイプは対応しない事とする。

【ImageResizeView.java】(マルチデバイス対応画像リサイズクラス)

public class ImageResizeView extends View{
	
	private Bitmap bmp;
	private int dp_w;
	private int dp_h;
	private int drow_h;
	private int drow_s;
	
	public ImageResizeView(Context context, int resource_name){
		super(context);
		// リソースからbitmapを作成
		bmp = BitmapFactory.decodeResource(context.getResources(), resource_name);
		// WindowManager取得
		WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
		// Displayインスタンス生成
		Display dp = wm.getDefaultDisplay();
		// ディスプレイサイズ取得
		dp_w = dp.getWidth();
		dp_h = dp.getHeight();
		// リサイズ画像の高さ
		drow_h = (dp_w / 2) * 3;
		// 描画始点の高さ
		drow_s = (dp_h - drow_h) / 2;
	}

	@Override
	protected void onDraw(Canvas canvas){
		// 背景色
		canvas.drawColor(Color.BLACK);
		// イメージ画像リサイズ
		bmp = Bitmap.createScaledBitmap(bmp, dp_w, drow_h , true);  
		// 描画
		canvas.drawBitmap(bmp, 0, drow_s, null);
	}
}

Viewクラスを継承して、onDrawメソッドをオーバーライドしてcanvasに描画する。

【Activity000.java】(Activityクラス)

public class Activity000 extends Activity {

	// リソースファイル名
	int resource_name = R.drawable.img00;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        
		setContentView(new ImageSizePut(this, resource_name));
	}
}
【出力結果】 画像マルチデバイス対応

【Android】リソースの画像サイズを取得する

リソースの画像サイズを取得してみる。

今回は、複数のActivityから利用したいので、別クラスを作成する。
Activityでインスタンスを生成して、リソースの画像を指定し、その画像サイズを受け取る。

【ImageSizeGet.java】
public class ImageSizeGet{

	// 画像のサイズを取得するメソッド
	public String getSize(Context context, int resource_name){
		// リソースからbitmapを作成
		Bitmap image = BitmapFactory.decodeResource(context.getResources(), resource_name);
		
		// 画像サイズ取得
		int width  = image.getWidth();
		int height = image.getHeight();
		
		// 画像サイズの文字列を返す
		String size = "w:" + width + ",h:" + height;
		return size;
	}
}

Context : アプリケーションの環境情報をグローバル(AndroidOSの全域)に受け渡しするためのインターフェース

【Activity000.java】
public class Activity000 extends Activity {

	// リソースファイル名を指定
	int resource_name = R.drawable.img01;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		// ImageSizeGetクラスをインスタンス化する
		ImageSizeGet put_text = new ImageSizeGet();
		
		// ImageSizeGetのgetNameメソッドを呼び出す
		String size = put_text.getSize(this, resource_name);

		// TextViewを準備
		TextView tv = new TextView(this);
		
		// テキスト出力
		tv.setText(size);
		setContentView(tv);
	}
}

Activityからメソッドを呼ぶ時に渡す引数Contextには、Activity自身を指すthisを指定する

【出力結果】
w:横幅,h:高さ

【PHP】POSTのデータを配列に代入する

フォームで送信した値をPOSTで受け取って、配列に代入してみる。

POSTのデータを配列に代入 【post.html】
<?php
	// 初期値設定
	$errer_message[] = ""; // エラーメッセージ配列
	$errer_no = 0; // ループ用エラーナンバー

	foreach($_POST as $key => $val){
		// データを配列に代入
		$data_arr[$key] = $val;
	}

	// 代入した配列の中身を確認
	print_r($data_arr);
?>

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>POSTのデータを配列に代入</title>
</head>
<body>
<div>
	<form method="POST" action="post.html">
		データ1:<input type="text" name="DATA1"><br/ >
		データ2:<input type="text" name="DATA2"><br/ >
		データ3:<input type="text" name="DATA3"><br/ >
		データ4:<input type="text" name="DATA4"><br/ >
		<input type="submit" value="送信">
		<input type="reset" value="取消">
	</form>
</div>
</body>
</html>
【出力結果】
Array ( [DATA1] => 東京都 [DATA2] => 神奈川県 [DATA3] => 千葉県 [DATA4] => 埼玉県 )

【JavaScript】読み込む外部CSSを動的に変える

JSで読み込む外部CSSを動的に変える

今回は、表示ボタンを押したときに入力するパスワードによって、
呼び出すCSSを変更して、表示する内容を変えるスクリプトを作ってみた。

■仕様■
・初期設定でBOXを非表示(display: none;)にしておく。
・「表示ボタン」を押したらダイアログを立ち上げ、パスワードを要求する。
・入力されたパスワードによって表示するCSSを変える。
 (パスワード「password01」→secret01.css、「password02」→secret02.cssを表示)
・display: none;→display: block;とする事で表示するBOXをコントロールする。
・パスワードが違う場合はダイアログ内に”パスワードが違います!” を表示する。

■処理の手順■
①表示ボタンが押されたら、passPrompt()関数が起動。
②入力できるダイアログを表示するprompt()が起動し、パスワードを要求。
③ダイアログのフォームに入力されたパスワードによって処理を変える。
④パスワードが一致したらcreateElement()、setAttribute()でlinkタグ、要素を生成する。
⑤getElementsByTagName()で指定要素内(headタグ)に子要素(linkタグ)を追加する。

【index.html】
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>JavaScriptパスワードテスト</title>
<link rel="stylesheet" href="css/common.css" type="text/css">

<script language="JavaScript"><!--
function passPrompt() {	
	myPassWord = window.prompt("パスワードを入力してください","");
	if(myPassWord == "password01"){
		// linkタグと要素を生成
		var css=document.createElement("link");
		css.setAttribute("rel","stylesheet");
		css.setAttribute("type","text/css");
		css.setAttribute("href","css/secret01.css");
		// 指定要素内(headタグ)に子要素(linkタグ)を追加
		document.getElementsByTagName("head")[0].appendChild(css);
	}else if(myPassWord == "password02"){
		var css=document.createElement("link");
		css.setAttribute("rel","stylesheet");
		css.setAttribute("type","text/css");
		css.setAttribute("href","css/secret02.css");
		document.getElementsByTagName("head")[0].appendChild(css);
	}else{
		alert( "パスワードが違います!" );
	}
}
// --></script>

</head>
<body>
<div id="container">
	<p class="pw"><a onClick="passPrompt()">表示ボタン</a></p>
	<ul>
		<li class="secret00">通常BOX</li>
		<li class="secret01">秘密BOX01</li><!-- "password01"で表示 -->
		<li class="secret02">秘密BOX02</li><!-- "password02"で表示 -->
	</ul>
	<a href="index.html">←戻る</a>
</div>
</body>
</html>
【common.css】(レイアウト用)
*{
	margin: 0;
	padding: 0;
}

#container {
	width: 300px;
	text-align: center;
	margin: auto;
	padding: 10px;
}

p.pw a{
	display: block;
	width: 160px;
	height: 42px;
	line-height: 42px;
	margin: auto;
	color: #FFFFFF;
	background: #000000;
}

li{
	display: block;
	width: 160px;
	height: 42px;
	line-height: 42px;
	border: 1px solid #000000;
	margin: 3px auto;
}

li.secret01,
li.secret02 {
	display: none;
}
【secret01.css】(表示切り替え用)
li.secret01 {
	display: block;
}
【secret02.css】(表示切り替え用)
li.secret02 {
	display: block;
}
【実行結果】 読み込むCSSを動的に変えるJS

【Android】SurfaceViewに対するタッチイベントで再描画する

SurfaceViewに対するイベント処理も、考え方は通常のViewでの処理とほとんどかわりません。

今回はSurfaceViewに描画した真顔のイラストをタッチ後、笑顔にする。

【準備画像】

SurfaceViewにタッチイベント
public class SampleSurfaceView extends SurfaceView implements SurfaceHolder.Callback{
	
	// 表示する画像
	private Bitmap image01;
	private Bitmap image02;
	private Bitmap image03;
	private Bitmap image02b;
     
	// コンストラクタ
	public SampleSurfaceView4(Context context) {
		super(context);
         
		getHolder().addCallback(this);
		// Bitmapリソースを用意
		image01 = BitmapFactory.decodeResource(getResources(), R.drawable.face);
		image02 = BitmapFactory.decodeResource(getResources(), R.drawable.eye);
		image02b = BitmapFactory.decodeResource(getResources(), R.drawable.eye2);
		image03 = BitmapFactory.decodeResource(getResources(), R.drawable.mouth);
	}
     
	// SurfaceView生成時に呼び出される(初期画面の描画)
	public void surfaceCreated(SurfaceHolder holder) {
    	
		doDraw(holder);
	}
     
	// SurfaceView変更時に呼び出される(画面の更新処理)
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
		// 処理がない場合も必要
	}
     
	// SurfaceView破棄時に呼び出される(画面の削除、削除後の処理)
	public void surfaceDestroyed(SurfaceHolder holder) {
		// 処理がない場合も必要
	}
    
	private void doDraw(SurfaceHolder holder) {
		// Canvas取得しロックする
		Canvas canvas = holder.lockCanvas();
		Paint paint = new Paint();
		//paint.setColor(Color.WHITE);
         
		// 描画処理
		canvas.drawBitmap(image01, 0, 0, paint);
		canvas.drawBitmap(image02, 0, 0, paint);
		canvas.drawBitmap(image03, 0, 0, paint);
         
		// LockしたCanvasを解放する
		holder.unlockCanvasAndPost(canvas);
	}
	
	private void onDraw(SurfaceHolder holder) {
		// Canvas取得しロックする
		Canvas canvas = holder.lockCanvas();
		Paint paint = new Paint();
		//paint.setColor(Color.WHITE);
         
		// 描画処理
		canvas.drawBitmap(image01, 0, 0, paint);
		canvas.drawBitmap(image02b, 0, 0, paint);
		canvas.drawBitmap(image03, 0, 0, paint);
         
		// LockしたCanvasを解放する
		holder.unlockCanvasAndPost(canvas);
	}
	
	// タッチイベント
	@Override
	public boolean onTouchEvent(MotionEvent event){
		onDraw(getHolder());
		return true;
	}
}
【実行結果】 SurfaceViewでオンタッチイベント

【Android】FrameLayout内でTextViewにマージンを指定する

前回、「FrameLayoutでSurfaceViewとTextViewと重ねて表示する」で作成したTextViewにマージンを指定する。
しかし、元となるレイアウトがFrameLayoutの場合、TextViewにmarginが設定できない。

FrameLayoutとTextViewの間にmarginが設定できるLinearLayoutを噛ませてやればうまくいく。

例)
FrameLayout -> TextView

FrameLayout -> LinearLayout -> TextView

【Activity000.java】

public class Activity000 extends Activity {

	// LayoutParamsにセットするパラメータを準備
	private final int FP = ViewGroup.LayoutParams.FILL_PARENT; 
	private final int WC = ViewGroup.LayoutParams.WRAP_CONTENT;
	private final int LFP = LinearLayout.LayoutParams.FILL_PARENT;
	private final int LWC = LinearLayout.LayoutParams.WRAP_CONTENT;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		// FrameLayoutを準備
		FrameLayout fl = new FrameLayout(this);
		setContentView(fl);
 
		// FrameLayoutにSurfaceViewをセットする
		fl.addView(new SampleSurfaceView2(this),new ViewGroup.LayoutParams(WC, WC));
        
		// SurfaceViewと重ねるTextViewを準備
		TextView tv = new TextView(this);
		tv.setText("SurfaceViewとTextViewを重ねる\nさらにTextViewにマージンを指定する");
		tv.setHeight(120);
		tv.setTextColor(Color.BLACK);
		tv.setBackgroundColor(Color.WHITE);
		
		// TextViewを入れるLinearLayoutを準備
		LinearLayout ll = new LinearLayout(this);
		LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LFP, LWC);
		lp.setMargins(10, 10, 10, 10);
		tv.setLayoutParams(lp);
		ll.addView(tv);
		
		// FrameLayoutにLinearLayoutをセットする
		fl.addView(ll, new ViewGroup.LayoutParams(FP, WC));
	}
}

setMarginsのパラメータ指定 : setMargins(左, 上, 右, 下)

【実行画面】

setMargins