ExpandableListViewっぽいものを独自で実装してみる

ExpandableListViewの使い方覚えるが面倒で、更にカスタマイズしてみたけど開閉ボタンの消し方が分からなかったので、結局それっぽものを自作してみた。


※drawableのxmlは省略


ヘッダーのレイアウト
list_header.xml

<?xml version="1.0" encoding="utf-8"?>
<com.sample.RowHeader
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:background="@drawable/header">
  <TextView
  	android:id="@+id/header"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:layout_gravity="center_vertical"
	android:textColor="#FFFFFFFF"
	android:textSize="20sp"/>  
</com.sample.RowHeader>

列のレイアウト
list_row.xml

<?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="wrap_content"
  android:background="@drawable/row">
  <TextView
  	android:id="@+id/row"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:layout_gravity="center_vertical"
	android:textColor="#FF000000"
	android:textSize="15sp"/>
</LinearLayout>

メイン
main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:id="@+id/virtual_listview"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
</LinearLayout>


ヘッダークラス
RowHeader.java

package com.sample;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;

public class RowHeader extends LinearLayout {
	public boolean mIsExpanded;
	public List<View> mRows;

	public RowHeader(Context context, AttributeSet attr) {
		super(context, attr);
		mIsExpanded = false;
		mRows = new ArrayList<View>();
	}

	public boolean isExpanded() {
		return mIsExpanded;
	}
	
	public void expand() {
		mIsExpanded = true;
		for (final View v : mRows) {
			v.setVisibility(View.VISIBLE);
		}
	}
	
	public void collapse() {
		mIsExpanded = false;
		for (final View v : mRows) {
			v.setVisibility(View.GONE);
		}
	}
	
	public List<View> getRows() {
		return mRows;
	}

	public int getRowCount() {
		return mRows.size();
	}

	public void addRow(View row) {
		mRows.add(row);
	}
}

メイン

package com.sample;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends Activity {
    private Map<String, List<String>> map;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        map = new HashMap<String, List<String>>() {
        	{ put("哺乳類", new ArrayList<String>() {{ add("イヌ"); add("ネコ"); add("イルカ"); }} ); }
        	{ put("鳥類", new ArrayList<String>() {{ add("スズメ"); add("ペンギン"); }} ); }
        	{ put("魚類", new ArrayList<String>() {{ add("ブリ"); }} ); }
        };
        
        // 擬似リストビュー
        final LinearLayout listView = (LinearLayout) findViewById(R.id.virtual_listview);        
        
        for (final Entry<String, List<String>> set : map.entrySet()) {
        	// ヘッダーのレイアウトを取得してテキストを設定
        	RowHeader headerLayout = (RowHeader) View.inflate(this, R.layout.list_header, null);
        	TextView headerText = (TextView) headerLayout.findViewById(R.id.header);
        	headerText.setText(set.getKey());
        	
        	// ヘッダークリックイベント
        	headerLayout.setOnClickListener(new OnClickListener() {				
				@Override
				public void onClick(View v) {
					RowHeader headerView = (RowHeader) v;
					
					// ヘッダーが親から見て何番目にあるかを取得
					int index = listView.indexOfChild(headerView);
					
					if (headerView.getRowCount() == 0) { // 0の場合は子どもがまだ生成されていない									
						List<String> rows = set.getValue();
						for (String row : rows) {
							LinearLayout rowLayout = (LinearLayout) View.inflate(MainActivity.this, R.layout.list_row, null);
							TextView rowText = (TextView) rowLayout.findViewById(R.id.row);
							rowText.setText(row);
							// ヘッダーの次のインデックスにどんどん追加
							listView.addView(rowLayout, ++index);
							headerView.addRow(rowLayout);
						}						
					}
					
					if (headerView.isExpanded()) {
						headerView.collapse(); // 閉じる
					} else {
						headerView.expand(); // 開く
					}
				}
			});
        	listView.addView(headerLayout);
        }
    }
}

こんな感じになるよ。ヘッダーをクリックして開閉。


アニメーションがうまくつかねー



>>2011/07/25 追記


expandableListView.setGroupIndicator(null)


でインジケーター消せた<<2011/07/25

node.jsに触れてみた

node.js公式

http://nodejs.org/

node.jsとは

公式のAbout抜粋
・ノンブロッキングI/O
・2MB/スレッドを割り当てるシステムよりメモリ効率がいいよ
デッドロックの心配なし
・よって誰でも高速なシステムが開発できるよ

インストール

wget http://nodejs.org/dist/node-v0.4.1.tar.gz
tar zxvf node-v0.4.1.tar.gz

cd node-v0.4.1

./configure
make
make install

Hello node.js!!

公式にあるサンプルを実行してみる。

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(8124, "127.0.0.1");
console.log('Server running at http://127.0.0.1:8124/');


サーバーにブラウザでアクセスすると「Hello World」が表示された!


なんだかオラわくわくしてきたぞ!
仕事で使うことはないけどな!!

初心者に厳しいAndroid開発環境構築

Androidネタがたまってきたので、まず開発環境構築から。


よくWindowsで…とかMacで…とかってあるけど、基本的にそんなの関係ねぇ、ということを認識して欲しいです。

eclipseのダウンロード


Eclipse公式(英語)
http://www.eclipse.org/downloads/
*1


デフォルトで日本語がいい!
MergeDoc
http://mergedoc.sourceforge.jp/
*2

Androidプラットフォームのインストールとエミュレータ起動


%SDK_HOME%tools/android を実行してAndroid SDK and AVD Managerを起動。
[Available packages]を選択し[Packages available for download]の[Android Repository]を展開。


Android SDK Tools
SDK Platform Android 3.0


にチェックをいれてインストール。(結構時間がかかる)


完了したら[Virtual devices]を選択し[New]。
NameとTarget(Android3.0)を設定して[Create AVD]。


作成したAVDを選択して[Start]で[Launch Options]が開くので[Scale display to real size]にチェックを入れて


Screen Size: 68
Monitor dip: 160 *3


で[Launch]。
*4


なぜかMOTOROLA XOOMが立ち上がります。(これまた結構時間がかかる)


MOTOROLA XOOM公式
http://www.motorola.com/Consumers/US-EN/Consumer-Product-and-Services/Tablets/ci.MOTOROLA-XOOM-US-EN.overview


>>2011/07/25 追記

XOOMじゃなくてこれがAndroid3.0のUIだったのね。。。<<2011/07/25


KDDI公式
http://www.kddi.com/corporate/news_release/2011/0228a/index.html

*5


Android ADT Pluginのインストール


プラグインリポジトリに以下を追加します。


Name: Android ADT Plugin (任意)
Location: https://dl-ssl.google.com/android/eclipse/


Developer Toolが出てくるのでチェックしてすべてインストール・再起動。

eclipseAndroid SDKのパスを設定

設定画面に[Android]の項目が増えてるので選択。


※ここでレポートを送信するみたいなダイアログが出るので消す。これ重要。


SDK LocationにAndroid SDKへのパスを設定しApply。
一覧にプラットフォーム名等ずらっとでれば設定完了。

Androidプロジェクトの作成

eclipseツールバーのこれクリック(たぶんデフォルトは左から5つ目)


Contents: Create project from existing sample
Build Target: Android 3.0


を選択して[finish]。

※最初はSamplesのプルダウンをApiDemosがおすすめ


生成されたプロジェクトを選択して[Run As]→[Android Application]でアプリケーションのインストールが開始・起動。


※コンソールにこんなエラーが出ちゃった場合

You must perform a full uninstall of the application. WARNING: This will remove the application data!
Please execute 'adb uninstall com.example.android.apis' in a shell.


%SDK_HOME%/platform-toolsにadbってのがあるので、書いてあるとおりに


adb uninstall com.example.android.apis


を実行し、再度Run As Android Applicationしましょう。


*1:軽量な Eclipse IDE for Java Developers あたりがおすすめ

*2:All in One なので重いから時間かかるけど

*3:dip(dod intdependent pixel) ちなみにプリンタでよく使うdpi(dod per inch)と間違えないよーに

*4:指定しなくてもいいけど、とんでもないことになるよ♪

*5:3G関係ないのになんでKDDIからやねん、基本料金云々か

Linq with inheritable Dao

Linq to SQLでDAOパターンかつCRUDな感じにしたくてInterfaceとかabstractでいろいろやっていたのだが、ジェネリックでシンプルに解決できそうなのでメモ。


DBの後始末等いろいろ雑なのはご愛嬌。


ポイントは

    public class BaseDao : IDisposable {

        protected MyDatabase ctx;

        public BaseDao() {
            this.ctx = new MyDatabase(Resources.ConnectionString);
        }

        public T Find<T>(T entity) where T : class {
            <del>try {</del>
                return (from o in this.ctx.GetTable<T>() where o == entity select o).Single<T>();
            <del>} catch (Exception e) {
                throw e;
            }</del>
        }

        public IEnumerable<T> FindAll<T>() where T : class {
            try {
                return from o in this.ctx.GetTable<T>() select o;
            } catch (Exception e) {
                throw e;
            }
        }

        public void Put<T>(T entity) where T : class {
            try {
                this.ctx.GetTable<T>().InsertOnSubmit(entity);
                this.ctx.SubmitChanges();
            } catch (Exception e) {
                throw e;
            }
        }

        public void Delete<T>(T entity) where T : class {
            try {
                this.ctx.GetTable<T>().DeleteOnSubmit(entity);
                this.ctx.SubmitChanges();
            } catch (Exception e) {
                throw e;
            }
        }

        #region IDisposable Members

        public MyDatabase GetContext() {
            return this.ctx;
        }

        public void Dispose() {
            this.ctx.Dispose();
        }

        #endregion
    }


あ、Updateがねぇや。まぁ、あとはこれを継承して使うと。


C#の情報って@○T(伏字)とかばっかで古いのしか見つからないんだけど、みんなどうしてんの??


今回参考にしたのはこちら。
http://blogs.msdn.com/b/msmossyblog/archive/2009/01/11/linq-to-sql-poormans-dao-crud.aspx


【2010/12/05 追記】
例外処理が仕方が間違っている。
Findについてはクエリをreturnしているだけなので、この時点では評価は行われていませんと。
これを実際にforeachなどするときに例外処理すべし。


参考にさせていただきました。
http://d.hatena.ne.jp/gsf_zero1/20091204/p3

eclipseでlift

やっぱりIDE使った方が学習効率がいってもんで、
eclipseにliftプロジェクトを作成してみます。


プロジェクトの作成まではこちら。
http://d.hatena.ne.jp/ktdk/20100507


作成したらディレクトリの中に入って、

mvn eclipse:eclipse


これでeclipseに必要なファイルとか作成されます。


eclipseを起動して、Scalaプラグインを入れましょう。


URL:http://www.scala-lang.org/scala-eclipse-plugin



プラグインのインストールが完了したら、
[ファイル]>[インポート]>[一般]>[既存プロジェクトをワークスペースへ]で
該当するプロジェクトをインポートします。



次にコマンドラインから以下を実行。

mvn -Declipse.workspace="[ワークスペースのディレクトリ名]" eclipse:add-maven-repo


あと、プロジェクトのプロパティからJavaのビルドパスを開いて、
変数にM2_REPOを追加する。(%USER%はユーザー名ディレクトリ)

M2_REPO = %USER%\.m2\repository


んで[実行]>[実行の構成]>[Scalaアプリケーション]に新規構成を追加し、


プロジェクト名:helloworld (例)
メインクラス:RunWebApp


と入力して実行。


Jettyが正常に起動すればOKです。


lift入門

scalaをいじってみたけど、実際に何か作ってみないとよくわからんので、
Twitterfoursquareも使っているというliftに入門してみた。

liftとは


めんどいので飛ばします


http://codezine.jp/article/detail/4310?p=2

環境


java, scala, maven のインストールは各サイト参照

プロジェクトの作成


ここからが本番です。以下を実行。

mvn archetype:generate -U \
-DarchetypeGroupId=net.liftweb \
-DarchetypeArtifactId=lift-archetype-basic \
-DarchetypeVersion=1.1-M8 \
-DarchetypeRepository=http://scala-tools.org/repo-releases \
-DremoteRepositories=http://scala-tools.org/repo-releases \
-DgroupId=demo.helloworld \
-DartifactId=helloworld \
-Dversion=1.0


archetype:create とご説明している方もいらっしゃいますが、現在は generate になっているみたい。
DarchetypeVersion は1.0だとサーバー起動後にアクセスエラーになりました。(scalaのバージョンが悪かったのかな?)


【2010/05/17 追記 >>】
http://scala-tools.org/repo-releases/net/liftweb に、
Archetypeごとのリポジトリがあるので、バージョンを随時チェック。
現時点の最新は 2.0-M5。
【<< 2010/05/17 追記】


んで

cd helloworld

mvn jetty:run

...

[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 5 seconds.


と実行して、http://localhost:8080/ にアクセスすると以下の画面が表示されます。
(初回起動時は結構時間がかかります)



起動ポートを変えたい場合は、

mvn jetty:run -Djetty.port=80


ってやればおk。


基本的な導入自体はすごく簡単だけど、やっぱり気をつけなくちゃいけないのが、
言語とフレームワークのバージョン。rails もなんか怪しいときあったし。


もっと実例が増えることに期待。