SQLの窓

2015年10月26日


Android で WebView を使ってWEBにあるデータベースのデータを取得する為のクラス

WebView は非表示で良く、HTTP の機能のみ必要です。その為、最低限必要な機能を WebView を継承して実装しています

DataWebView.java
package sample.lightbox.androidbind1017;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.AttributeSet;
import android.util.Log;
import android.webkit.WebView;
import android.webkit.WebViewClient;

/**
 * Created by lightbox on 2015/10/23.
 */
public class DataWebView extends WebView {

	private String startPage = null;
	private String initPage = "http://winofsql.jp/002.php";

	public DataWebView(Context context) {
		super(context);
		init();
	}
	public DataWebView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}
	public DataWebView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init();
	}

	private void init(){
		if (!isInEditMode() ) {

			// 必ず必要な JavaScript を有効にする設定
			this.getSettings().setJavaScriptEnabled(true);
			// 必ず必要な設定
			this.setWebViewClient(new WebViewClient() {

				// 必ず必要な設定 : 常に WebView 内でページを表示する為
				@Override
				public boolean shouldOverrideUrlLoading(WebView view, String url) {
					Log.i("lightbox", "shouldOverrideUrlLoading" + url);
					// 現 URL の為 false になるようです。必要ならば、return false; と明記します
					return super.shouldOverrideUrlLoading(view, url);
				}

				// オプション : 表示されたページの URL を変数にセット
				@Override
				public void onPageStarted(WebView view, String url, Bitmap favicon) {
					super.onPageStarted(view, url, favicon);

					Log.i("lightbox", "onPageStarted:" + url);
					startPage = url;

				}

				// オプション : ページを表示し終わってから発生するイベント
				@Override
				public void onPageFinished(WebView view, String url) {
					super.onPageFinished(view, url);

				}
			});


			this.loadUrl(initPage);
		}
	}

}


Android と WebView 内の JavaScript とのインターフェイスです

JavaScriptAccess.java
package sample.lightbox.androidbind1017;

import android.util.Log;
import android.webkit.JavascriptInterface;

public class JavaScriptAccess {
	// Webページからデータを取得するイベント用
	public interface OnGetWebDataListener {
		abstract public void onWebGetDataListener( String textData );
	}

	private OnGetWebDataListener ogwdl = null;

	public JavaScriptAccess( OnGetWebDataListener ogwdl ) {
		this.ogwdl = ogwdl;
	}

	// Webページ上の JavaScript から、Android Studio の logcat に表示します
	@JavascriptInterface
	public void logcat(String message) {
		Log.i("lightbox", message);
	}

	// コンストラクタで取得したインターフェイスのインスタンス内のメソッドを
	// 呼び出して、Webページから取得したデータを渡します
	@JavascriptInterface
	public void toAndroid(String message) {
		this.ogwdl.onWebGetDataListener(message);
	}


}


JavaScriptAccess によって(インターフェイス経由の onWebGetDataListener の呼び出し)、JavaScript から呼び出された時のイベントとして、こちら側で処理が可能になっています。

但し、非同期の処理の為、UI スレッドへは直接アクセスできないので、Handler を使用しています( Handler は、UI スレッド側の定義です )

MainActivity での実装部分
		// *************************************************
		// WebView
		// *************************************************
		wv = (DataWebView) MainActivity.this.findViewById(R.id.webView);
		// *************************************************
		// WebView の準備 ( 開始 )
		// *************************************************
		// Webページとのインターフェイスを登録します
		// Webページ上からは、androidObject.toAndroid で呼ぶ事ができます
		// (toAndroid は、@JavascriptInterface で登録したメソッド)
		wv.addJavascriptInterface(new JavaScriptAccess(new JavaScriptAccess.OnGetWebDataListener() {
			@Override
			public void onWebGetDataListener(String textData) {

				try {
					Gson gson = new Gson();
					syain = gson.fromJson(textData, Syain.class);

					// 別スレッドから UI スレッドへのアクセス
					handler.post(new Runnable() {
						@Override
						public void run() {

							// *************************************
							// 画面表示
							// *************************************
							binding.setUser(syain);
							// ボタンイベント用のデータをセット
							ba.setData(binding, syain);

							if (!syain.kj.equals("ERROR")) {

								// 現在の内容でコントロールセット( fromJson 用なので、null 指定 )
								syain.setSeibetuControl(null);
								syain.setSyozokuControl(null, getResources().getStringArray(R.array.list_value));
								syain.setBirthControl(null);

								// フォーカスオフ
								EditText et = (EditText) MainActivity.this.findViewById(R.id.editText);
								im.hideSoftInputFromWindow(et.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);

							}

						}
					});

				} catch (Exception e) {
					e.printStackTrace();
				}

			}
		}), "androidObject");



posted by lightbox at 2015-10-26 15:46 | Comment(0) | Android Studio 2 | このブログの読者になる | 更新情報をチェックする

Android の Data Binding( "クラス > 画面" の片方向 )における特殊コントロールの処理をデータクラス内に実装する

画面定義

Android の 公式の Data Binding は、データクラスから 画面への片方向です。また、対応しているのは setText メソッドを持つコントロールのようなので、ここで利用している NumberPickerSpinnerDatePicker では、個別にデータクラスのデータをセットする処理を実装する必要があるので、データクラス内に全て収めました。

このデータクラスは、Google Gson を使用して JSON から一括でデータをセットする事を想定しています。

注 : Data Binding と Google Gson を利用する事を目的としているため、画面用のデータは全て String で定義し、Getter や Setter を定義していません。必要ならば、Getter や Setter で拡張し、その場合でも Data Binding と Google Gson は正しく動作します

Syain クラス
import android.databinding.BaseObservable;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.DatePicker;
import android.widget.NumberPicker;
import android.widget.Spinner;

import java.util.Arrays;

public class Syain extends BaseObservable {

	// シリアライズ・デシリアライズをしない( static )
	static public MainActivity context = null;
	// NumberPicker 用
	static public NumberPicker np = null;
	static public String[] nums = {"男性","女性","不明"};
	static public int[] values = {-10,20,100};
	// Spinner 用
	static public Spinner sp = null;
	// DatePicker 用
	static public DatePicker dp = null;

	public String scode;
	public String kj;
	public String furi;
	public String syozoku;
	public String seibetu;
	public String kyuyo;
	public String teate;
	public String kanri;
	public String birth;
	public String sname;

	public Syain() {
		this.scode = "";
		this.kj = "初期状態";
		this.furi = "";
		this.syozoku = "";
		this.seibetu = "";
		this.kyuyo = "";
		this.teate = "";
		this.kanri = "";
		this.birth = "";
		this.sname = "";
	}

	// ******************************************
	// NumberPicker 用
	// ******************************************
	public void setupSeibetuControl() {
		np.setMinValue(0);
		np.setMaxValue(2);
		np.setDisplayedValues(nums);
		np.setValue(1);

	}
	public void setSeibetuControl(String seibetu) {
		if ( seibetu != null ) {
			this.seibetu = seibetu;
		}
		np.setValue(Integer.parseInt(this.seibetu));
	}
	public void getSeibetuControl() {
		this.seibetu = Integer.toString(np.getValue());
	}

	// ******************************************
	// Spinner 用
	// ******************************************
	public void setupSyozokuControl(String[] list_data) {
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(
				context,
				android.R.layout.simple_spinner_item);
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		adapter.addAll(list_data);
		sp.setAdapter(adapter);
	}
	public void setSyozokuControl(String syozoku,String[] list_value) {
		if ( syozoku != null ) {
			this.syozoku = syozoku;
		}
		int idx = Arrays.binarySearch(list_value,this.syozoku);
		sp.setSelection(idx);
	}
	public void getSyozokuControl(String[] list_value) {
		int idx = sp.getSelectedItemPosition();
		this.syozoku = list_value[idx];
	}

	// ******************************************
	// DatePicker 用
	// ******************************************
	public void setupBirthControl(Boolean spinners, Boolean calendar) {
		dp.setSpinnersShown(spinners);
		dp.setCalendarViewShown(calendar);
	}
	public void setBirthControl(String birth) {
		if ( birth != null ) {
			this.birth = birth;
		}
		if ( this.birth != null ) {
			String dt[] = this.birth.split("-");
			if ( dt.length == 3 ) {
				dp.updateDate(Integer.parseInt(dt[0]), Integer.parseInt(dt[1])-1, Integer.parseInt(dt[2]));
			}
		}
	}
	public void getBirthControl() {
		this.birth = String.format("%d/%d/%d",dp.getYear(),dp.getMonth()+1,dp.getDayOfMonth());
	}


}

※ 再利用の為、先頭のパッケージ記述は削除しています

各コントロール用の Getter の引数について

Google Gson がデータを全てセットしてくれるので、その直後の処理としては、引数を必要としません。ですから、Google Gson のデシリアライズで受け取った値を使用する場合は、引数に null を使用します。
// 現在の内容でコントロールセット( fromJson 用なので、null 指定 )
syain.setSeibetuControl(null);
syain.setSyozokuControl(null, getResources().getStringArray(R.array.list_value));
syain.setBirthControl(null);


BaseObservable の継承について

ここでは、必要無かったのでこの BaseObservable の機能を使用していませんが、データクラス内のデータを個別に変更してリアルタイムで画面に反映させる場合に BaseObservable の通知機能を使います。しかし、自動生成されるバインド用のクラスの invalidateAll() を使ったほうが簡単であると思います。( Google Gson は、Setter を使用しないので利用できませんでした )

static フィールドについて

Google Gson のシリアライズとデシリアライズの対象外にする為に使用しています。当然、クラス共通となる為、画面定義と一対一と言う認識での実装です。



posted by lightbox at 2015-10-26 13:49 | Comment(0) | Android Studio 2 | このブログの読者になる | 更新情報をチェックする

Android の Data Binding における include を使用した画面分割

Android デベロッパーの Data Binding Guide に書かれていますが、bind:user="@{user}" のように variable で指定した変数を引き継ぐだけです。



この記述は、引き継がれた( include された) 画面にも記述して、さらに第三画面を include できます。



注意 : デザイン画面でエラーのようなものが出る場合は、( とりあえず Clean Project を実行して ) 左上の x をクリックして閉じて下さい。( カスタム要素のせいです )


画面全体のソースコード

引き継がれた( include された) 画面
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:bind="http://schemas.android.com/apk/res-auto"
        tools:context=".MainActivity">

    <data>
        <variable
            name="user"
            type="sample.lightbox.androidbind1017.Syain"/>
    </data>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{user.syozoku}"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:id="@+id/textView3"
            android:layout_margin="4dp"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{user.sname}"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:id="@+id/textView4"
            android:layout_margin="4dp"/>

        <NumberPicker
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/numberPicker"/>

        <Spinner
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/spinner"
            android:spinnerMode="dropdown"/>

        <DatePicker
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/datePicker"
            android:datePickerMode="spinner"/>

        <include
            layout="@layout/ex_contents2"
            android:id="@+id/ex2"
            bind:user="@{user}"/>

    </LinearLayout>
</layout>


第三画面
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:bind="http://schemas.android.com/apk/res-auto"
        tools:context=".MainActivity">

    <data>
        <variable
            name="user"
            type="sample.lightbox.androidbind1017.Syain"/>
    </data>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">


        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{user.kj}"
            android:id="@+id/editText2"
            android:background="@drawable/border"
            android:padding="5dp"/>

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TOP"
            android:id="@+id/button4"/>

    </LinearLayout>
</layout>

Data Binding 画面の注意事項

画面定義内は常に英数字・記号を使用する必要があります

現時点では、画面内の文字列に日本語を使用できません。実際使う場合は、初期値を直接書き込む場合とバインド用の変数に使う場合ですが、前者はリソースとして定義して日本語を使わずに参照擦れば動作します。しかし、後者では使え無い場合があります(使える場合もある)。


posted by lightbox at 2015-10-26 10:10 | Comment(0) | Android Studio 2 | このブログの読者になる | 更新情報をチェックする

2015年10月16日


Android : WebView 経由のデータベースアプリケーション



HTTP で直接通信すると手っ取り早いですが、いかんせん汎用性に欠けます。WebView を使うと途中のデバッグそのものが、他の開発に転用できそうなのでいいと思います。とにかく、いろいろ手順が満載です。

1) Android で入力した値を引数としてページに渡す

これは一番簡単です。javascript:以降に関数名を記述して、引数を文字列として埋め込んで loadUrl するだけです。
EditText et = (EditText) MainActivity.this.findViewById(R.id.editText);
String scode =((EditText) MainActivity.this.findViewById(R.id.editText)).getText().toString();
String callString = String.format("javascript:getWebPageData(\"%s\")",scode);
wv.loadUrl(callString);
全体のソースコードはこちら

2) Webページでは、jQueryでサーバーから必要な値を取得
$.get("dbdata_json.php?scode="+scode,function( data ){
	if ( typeof androidObject !== 'undefined' ) {
		// サーバから受け取った application/json データ
		// を文字列に変換して Android に渡します
		androidObject.toAndroid(JSON.stringify(data));
	}
	else {
		// 通常のブラウザではこちらが実行されます
		console.log(JSON.stringify(data,null,"   "));
	}
})
全体のソースコードはこちら

3) サーバーのPHPは、DBのデータをJSONで返す
$_GET["scode"] = str_replace("'","''",$_GET["scode"]);
$result = $connect->query("select * from 社員マスタ where 社員コード = '{$_GET["scode"]}'"); 
if ( !$result ) {
	die('クエリーに誤りがあります : ' . $connect->error );
}

// 内容を書き込むファイルの準備
$log_file = "rowdata_002.json";
file_put_contents( $log_file,"" );

$check = false;
while ($row = $result->fetch_array($db_data_type)) {

	$check = true;
	print json_encode($row,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
	print "\n";

	// ファイルに追加出力
	file_put_contents( $log_file, print_r(json_encode($row,$json_type)."\n",true), FILE_APPEND );
}

全体のソースコードはこちら

file_put_contents は、デバッグ用です。処理には直接必要ありません

4) WEBページは JSON の文字列を Android に送る

さて、ここが重要な Android 側のインターフェイスの定義が必要なところです。専用のクラスを作成して、Activity 内の変数を使いやすいように、インターフェイスを定義して処理を外に出します

JavaScriptAccess クラス
package sample.lightbox.webbrowser;

import android.util.Log;
import android.webkit.JavascriptInterface;

/**
 * Created by lightbox on 2015/09/24.
 */
public class JavaScriptAccess {
	// Webページからデータを取得するイベント用
	public interface OnGetWebDataListener {
		abstract public void onWebGetDataListener( String textData );
	}

	private OnGetWebDataListener ogwdl = null;

	public JavaScriptAccess( OnGetWebDataListener ogwdl ) {
		this.ogwdl = ogwdl;
	}

	// Webページ上の JavaScript から、Android Studio の logcat に表示します
	@JavascriptInterface
	public void logcat(String message) {
		Log.i("lightbox", message);
	}

	// コンストラクタで取得したインターフェイスのインスタンス内のメソッドを
	// 呼び出して、Webページから取得したデータを渡します
	@JavascriptInterface
	public void toAndroid(String message) {
		this.ogwdl.onWebGetDataListener(message);
	}


}

この定義を使用しているのは、WebView の addJavascriptInterface メソッドですが、これによって、WEBページから Andrpod のこのクラスの内部で定義されたメソッドを実行可能になります。

全体のソースコード

WEBページから呼ばれると、onWebGetDataListener 内が実行されます

5) JSON文字列を Gson で Android 内のオブジェクトに変換

Syain というクラスを定義しておいて、Google Gson で gson.fromJson(textData,Syain.class) を実行してインスタンを取得します。

▼ Syain クラス
public class Syain {
	String 社員コード;
	String 氏名;
	String フリガナ;
	String 所属;
	int 性別;
	String 作成日;
	String 更新日;
	int 給与;
	int 手当;
	String 管理者;
	String 生年月日;
}

日本語を使っているのは、テーブル定義が日本語なのでそのまま利用できるからです。(Google Gson を使用しますが、JSON 側の名前と一致したものがこちらにあれば良く、全てある必要はありませんし、JSON側に無いものがあってもかまいません)

6) UI スレッドへその値を送る

要するに画面に値をセットするだけですが、JavaScript のインターフェイスが別スレッドなので、Handler を使用します
try {
	syain = gson.fromJson(textData,Syain.class);

	// 別スレッドから UI スレッドへのアクセス
	handler.post(new Runnable() {
		@Override
		public void run() {
			TextView tv = (TextView) MainActivity.this.findViewById(R.id.textView);
			tv.setText(syain.氏名);
		}
	});

} catch (Exception e) {
	e.printStackTrace();
}
全てのソースコード

dbdata_json.php は、データベースの部分なので、WEB上にも用意しました
(※ WEB上のソースコードはこちら)

実機でテストする場合必要なので、001.php も WEB上に用意しました



posted by lightbox at 2015-10-16 12:31 | Comment(0) | Android Studio 2 | このブログの読者になる | 更新情報をチェックする

2015年10月03日


PHP で Windows標準のオブジェクト(CDO.Message)とGMail を使ってメール送信

ひさしぶりにテスト( Windows7 ) しようとすると、Gmail からエラーが返って来ましたが、Gmail 側で安全性の低いアプリの許可を『有効』にする必要がありました。

また、php 側では、php_com_dotnet.dll を php.ini で有効にする必要があります。

※ CDO.Message に関する詳細は、ソース内に URL を記述しています

関連する記事

Windows標準のオブジェクト(CDO.Message)とGMail を使ってメール送信

本来は、VBScript で実行するものですが、PHP が分かる人なら、こちらのほうがいろいろ応用がきいて使い勝手もいいと思います。

▼ バッチファイル
------------------------------------------------------
@echo off
setlocal
set PATH=c:\php;%PATH%

php mail.php "題名" "本文\nで す\nよ"

endlocal
------------------------------------------------------

mail.php
<?php
// ***********************************************
// バッチファイル内容
// setlocal は、環境変数を一時的に設定する為に使用します
// php.exe は、c:\php にあります
// ***********************************************
/*
@echo off
setlocal
set PATH=c:\php;%PATH%

php mail.php "題名" "本文\nで す\nよ"

endlocal
*/

// ***********************************************
// php.ini で必要な拡張
// ***********************************************
/*
extension=php_com_dotnet.dll
*/

// ***********************************************
// Gmail 側の設定
// ***********************************************
/*
安全性の低いアプリの許可を『有効』にする

https://myaccount.google.com/security?pli=1#connectedapps
*/

// ***********************************************
// PHP の処理開始
// ***********************************************
$strFrom = "私です <ユーザ名@gmail.com>";
$strTo = "あなたです <宛先メールアドレス>";

$strServer = "smtp.gmail.com";
$nPort = 465;
$strUser = "ユーザ名@gmail.com";
$strPass = "パスワード!";

// ***********************************************
// CDO.Message( CDO for Windows 2000 )
// ***********************************************
$cdo = new COM( "CDO.Message" );

$cdo->From = $strFrom;
$cdo->To = $strTo;

// ***********************************************
// 題名
// ***********************************************
$cdo->Subject = $argv[1];

// ***********************************************
// バッチファイルで引渡した本文文字列内の \n を実際の改行に変換
// ***********************************************
$data = str_replace( "\\n", "\n", $argv[2] );
$cdo->Textbody = $data;

// ***********************************************
// 送信情報オプション
// ***********************************************
$cdo->Cc = "メールアドレス1,メールアドレス2";
//$cdo->Bcc = "";
$cdo->Htmlbody = "<img src=\"http://winofsql.jp/image/winofsql.png\">";

// ***********************************************
// ファイル添付
// ***********************************************
$cdo->AddAttachment( "C:\\Users\\lightbox\\Desktop\\画像\\_img.jpg" );

// cdoSendUsingPort : 2 : Send the message using the network (SMTP over the network)
// https://msdn.microsoft.com/en-us/library/ms527265.aspx.
$cdo->Configuration->Fields["http://schemas.microsoft.com/cdo/configuration/sendusing"] = 2;

// The name (DNS) or IP address of the machine hosting the SMTP service through which messages are to be sent.
// https://msdn.microsoft.com/en-us/library/ms527294.aspx
$cdo->Configuration->Fields["http://schemas.microsoft.com/cdo/configuration/smtpserver"] = $strServer;

// The port on which the SMTP service specified by the smtpserver field is listening for connections.
// https://msdn.microsoft.com/en-us/library/ms526227.aspx
$cdo->Configuration->Fields["http://schemas.microsoft.com/cdo/configuration/smtpserverport"] = $nPort;

// Indicates that SSL should be used when sending messages using the SMTP protocol over the network.
// https://msdn.microsoft.com/en-us/library/ms526975.aspx
$cdo->Configuration->Fields["http://schemas.microsoft.com/cdo/configuration/smtpusessl"] = true;

// Specifies the authentication mechanism to use when authentication is required to send messages
// to an SMTP service using a TCP/IP network socket.
// https://msdn.microsoft.com/en-us/library/ms526600.aspx
// 1 : Use basic (clear-text) authentication
// https://msdn.microsoft.com/en-us/library/ms526961.aspx
$cdo->Configuration->Fields["http://schemas.microsoft.com/cdo/configuration/smtpauthenticate"] = 1;

// ユーザとパスワード
$cdo->Configuration->Fields["http://schemas.microsoft.com/cdo/configuration/sendusername"] = $strUser;
$cdo->Configuration->Fields["http://schemas.microsoft.com/cdo/configuration/sendpassword"] = $strPass;

$cdo->Configuration->Fields->Update();

$cdo->Send();

// ***********************************************
// レジストリ内容
// ***********************************************
/*
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\CLSID\{CD000001-8B95-11D1-82DB-00C04FB1625D}]
@="CDOMessage Class"

[HKEY_CLASSES_ROOT\CLSID\{CD000001-8B95-11D1-82DB-00C04FB1625D}\InprocServer32]
@="C:\\Windows\\system32\\cdosys.dll"
"ThreadingModel"="Both"

[HKEY_CLASSES_ROOT\CLSID\{CD000001-8B95-11D1-82DB-00C04FB1625D}\ProgID]
@="CDO.Message.1"

[HKEY_CLASSES_ROOT\CLSID\{CD000001-8B95-11D1-82DB-00C04FB1625D}\Programmable]

[HKEY_CLASSES_ROOT\CLSID\{CD000001-8B95-11D1-82DB-00C04FB1625D}\VersionIndependentProgID]
@="CDO.Message"
*/
?>

参考情報

メーラーからGmailへの接続時に認証(パスワード)のエラーが生じる場合の対処方法



posted by lightbox at 2015-10-03 21:44 | PHP + 通信 | このブログの読者になる | 更新情報をチェックする

2015年10月01日


Android : DatePickerDialog で、4種類のダイアログを使い分ける( spinner と calendar の組み合わせ )

Android 5.1 ですが、プログラムからスタイルの 1属性を(容易には)変更できないようなので、二つのスタイルを用意して必要な DatePickerDialog を作成して使用します。何もしないと、大きなカレンダーになり、初期表示の日付の前後の日付選択は簡単ですが、年月の変更をしたい場合は、スピナーを組み合わせる必要があります。

しかし、スピナーへの変更がスタイル経由でしかできないので、DatePickerDialog のコンストラクタでテーマを指定できるほうを使って適宜選択します。





<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AppTheme" parent="android:Theme.Material.Light">
    </style>

    <style name="MyDialogTheme" parent="android:Theme.Material.Light.Dialog">
        <item name="android:datePickerStyle">@style/MyDatePicker</item>
    </style>
    <style name="MyDialogTheme2" parent="android:Theme.Material.Light.Dialog">
        <item name="android:datePickerStyle">@style/MyDatePicker2</item>
    </style>

    <style name="MyDatePicker" parent="android:Widget.Material.DatePicker">
        <item name="android:datePickerMode">spinner</item>
    </style>
    <style name="MyDatePicker2" parent="android:Widget.Material.DatePicker">
        <item name="android:datePickerMode">calendar</item>
    </style>
</resources>


MainActivity
package sample.lightbox.calendar;

import android.app.Activity;
import android.app.DatePickerDialog;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.DatePicker;

import java.util.Calendar;

public class MainActivity extends Activity {

	private DatePickerDialog spinnerDatePicker = null;
	private DatePickerDialog calendarDatePicker = null;

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

		final Calendar calendar = Calendar.getInstance();
		int year = calendar.get(Calendar.YEAR);
		int monthOfYear = calendar.get(Calendar.MONTH);
		int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);

		spinnerDatePicker = new DatePickerDialog(
				MainActivity.this,
				R.style.MyDialogTheme,
				new DatePickerDialog.OnDateSetListener() {
					@Override
					public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
						String buffer = String.format("%4d/%02d/%02d",year,monthOfYear+1,dayOfMonth);
						Log.i("lightbox",buffer);
					}
				},year,monthOfYear,dayOfMonth);

		calendarDatePicker = new DatePickerDialog(
				MainActivity.this,
				R.style.MyDialogTheme2,
				new DatePickerDialog.OnDateSetListener() {
					@Override
					public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
						String buffer = String.format("%4d/%02d/%02d",year,monthOfYear+1,dayOfMonth);
						Log.i("lightbox",buffer);
					}
				},year,monthOfYear,dayOfMonth);


		MainActivity.this.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				spinnerDatePicker.getDatePicker().setSpinnersShown(true);
				spinnerDatePicker.getDatePicker().setCalendarViewShown(false);
				spinnerDatePicker.show();
			}
		});

		MainActivity.this.findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				spinnerDatePicker.getDatePicker().setSpinnersShown(false);
				spinnerDatePicker.getDatePicker().setCalendarViewShown(true);
				spinnerDatePicker.show();
			}
		});

		MainActivity.this.findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				spinnerDatePicker.getDatePicker().setSpinnersShown(true);
				spinnerDatePicker.getDatePicker().setCalendarViewShown(true);
				spinnerDatePicker.show();
			}
		});

		MainActivity.this.findViewById(R.id.button4).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				calendarDatePicker.show();
			}
		});
	}

}

フラグメントバージョンは、Android Developer の Creating a Date Picker を参考にしますが、現状では getSupportFragmentManager では無く getFragmentManager を使用します。

また、常に spinner 側を使用するのであれば、メインテーマの中に、以下を入れてしまえばいいはずです。
<item name="android:dialogTheme">@style/MyDialogTheme</item>
参考


posted by lightbox at 2015-10-01 03:04 | Comment(0) | Android Studio 2 | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します


Windows
container 終わり

フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

Android SDK ポケットリファレンス
改訂版 Webデザイナーのための jQuery入門
今すぐ使えるかんたん ホームページ HTML&CSS入門
CSS ドロップシャドウの参考デモ
Google Hosted Libraries
cdnjs
BUTTONS (CSS でボタン)
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり