アイコンのサイズ

ランチャー用アイコンを作成する時用にいつも忘れるからメモ。
google playにアプリをアップロードするときに512px x 512pxが必要になるから、これを最初に作成しとておく。

 フォルダ サイズ 
 drawable-hdpi  72px x 72px
 drawable-mdpi  48px x 48px
 drawable-xhdpi  96px x 96px
 drawable-xxhdpi  144px x 144px

アドレス帳から電話番号とメールアドレスを取得する

アドレス帳から電話番号とメールアドレスを取得したい。
ということで、サンプルを作成してみた。イメージとしてはアドレス帳を表示して電話番号とメールアドレスを取得する。
電話番号、メールアドレスが複数ある場合はダイアログを出して選択させる。

作成するプログラム

MainActivity.java

作成するレイアウトファイル

activity_main.xml

MainActivity.java

アドレス帳の表示として、以下のコードを実行

Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent, REQUEST_CODE_MAIL_ADDRESS);

「onActivityResult」で値を受け取るイメージ。電話番号、メールアドレスが複数ある場合は
ダイアログフラグメントで選択する。以下ソース。

import android.os.Bundle;
import android.provider.ContactsContract;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.ContentResolver;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {
	private static final int REQUEST_CODE_PHONE_NUMBER = 0;
	private static final int REQUEST_CODE_MAIL_ADDRESS = 1;
	private EditText etName1;
	private EditText etPhoneNumber;
	private Button btGetPhoneNumber;
	private EditText etName2;
	private EditText etMailAddress;
	private Button btGetMailAddress;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		etName1 = (EditText)this.findViewById(R.id.name1);
		etPhoneNumber = (EditText)this.findViewById(R.id.phone_number);
		btGetPhoneNumber = (Button)this.findViewById(R.id.get_phone_number);
		etName2 = (EditText)this.findViewById(R.id.name2);
		etMailAddress = (EditText)this.findViewById(R.id.mail_address);
		btGetMailAddress = (Button)this.findViewById(R.id.get_mail_address);
		
		// 電話番号の取得
		btGetPhoneNumber.setOnClickListener(new OnClickListener() {
        	public void onClick(View v) {
        		Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
				startActivityForResult(intent, REQUEST_CODE_PHONE_NUMBER);
        	}
        });
		
		// メールアドレスの取得
		btGetMailAddress.setOnClickListener(new OnClickListener() {
        	public void onClick(View v) {
        		Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
				startActivityForResult(intent, REQUEST_CODE_MAIL_ADDRESS);
        	}
        });
	}

	/**
     * 起動したActivityの戻り
     */	
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		switch (requestCode) {
		case REQUEST_CODE_PHONE_NUMBER:
			// 電話番号の取得
			if (resultCode == Activity.RESULT_OK) {
				onPhoneNumberAddressBookResult(data);
			}
			break;
		case REQUEST_CODE_MAIL_ADDRESS:
			// メールアドレスの取得
			if (resultCode == Activity.RESULT_OK) {
				onMailAddressAddressBookResult(data);
			}
			break;
		default:
		}
	}
	
	/**
     * アドレス帳(電話番号)の表示
     */
	private void onPhoneNumberAddressBookResult(Intent data) {
		String[] phoneNumbers = new String[0];
		ContentResolver contentResolver = this.getContentResolver();
		Cursor c = contentResolver.query(data.getData(), null, null, null, null);
		String id = "";
		String name = "";
		if (c.moveToFirst()) {
			// 選択された人のidの取得
			id = c.getString(c.getColumnIndex(ContactsContract.Contacts._ID));
			name = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
			
			// 選択された人の電話番号をすべて取得
			Cursor phoneC = contentResolver.query(
						ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
						null,
						ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + id,
						null,
						null);
			if (phoneC.moveToFirst()) {
				phoneNumbers = new String[phoneC.getCount()];
				int count = 0;
				do {
					phoneNumbers[count] = phoneC.getString(
							phoneC.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DATA));
					count++;
				} while (phoneC.moveToNext());
			}
			phoneC.close();
		}
		c.close();
		
		// 名前をセット
		etName1.setText(name);
		
		// 選択者が電話番号を持っていない場合
		if (phoneNumbers.length <= 0) {
			return;
		}
		
		// 電話番号が1つの場合
		if (phoneNumbers.length == 1) {
			etPhoneNumber.setText(phoneNumbers[0]);
			return;
		}
		
		// シングル選択ダイアログフラグメント
		SingleSelectDialogFragment fragment = SingleSelectDialogFragment.newInstance(
				R.string.dialog_title_select_phone_number, phoneNumbers, 0);
		fragment.show(getFragmentManager(), "phone_number_select");
	}
	
	/**
     * アドレス帳(メールアドレス)の表示
     */
	private void onMailAddressAddressBookResult(Intent data) {
		String[] mailAddresses = new String[0];
		ContentResolver contentResolver = this.getContentResolver();
		Cursor c = contentResolver.query(data.getData(), null, null, null, null);
		String id = "";
		String name = "";
		if (c.moveToFirst()) {
			// 選択された人のidの取得
			id = c.getString(c.getColumnIndex(ContactsContract.Contacts._ID));
			name = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
			
			// 選択された人のメールアドレスをすべて取得
			Cursor mailC = contentResolver.query(
						ContactsContract.CommonDataKinds.Email.CONTENT_URI,
						null,
						ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = " + id,
						null,
						null);
			if (mailC.moveToFirst()) {
				mailAddresses = new String[mailC.getCount()];
				int count = 0;
				do {
					mailAddresses[count] = mailC.getString(
							mailC.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
					count++;
				} while (mailC.moveToNext());
			}
			mailC.close();
		}
		c.close();
		
		// 名前をセット
		etName2.setText(name);
		
		// 選択者がメールアドレスを持っていない場合
		if (mailAddresses.length <= 0) {
			return;
		}
		
		// メールアドレスが1つの場合
		if (mailAddresses.length == 1) {
			etMailAddress.setText(mailAddresses[0]);
			return;
		}
		
		// シングル選択ダイアログフラグメント
		SingleSelectDialogFragment fragment = SingleSelectDialogFragment.newInstance(
				R.string.dialog_title_select_mail_address, mailAddresses, 1);
		fragment.show(getFragmentManager(), "mail_address_select");
	}
	
	/**
     * 電話番号セレクト
     */
	public void onPhoneNumberSelect(String phoneNumber) {
		etPhoneNumber.setText(phoneNumber);
	}
	
	/**
     * メールアドレスセレクト
     */
	public void onMailAddressSelect(String mailAddress) {
		etMailAddress.setText(mailAddress);
	}
	
	/**
     * シングルセレクトダイアログフラグメント
     */
	public static class SingleSelectDialogFragment extends DialogFragment {
		private String selectedItem = "";
		
		public static SingleSelectDialogFragment newInstance(int title, String[] items, int selectKind) {
			SingleSelectDialogFragment fragment = new SingleSelectDialogFragment();
			Bundle args = new Bundle();
			args.putInt("title", title);
			args.putStringArray("items", items);
			args.putInt("select_kind", selectKind);
			fragment.setArguments(args);
			
			return fragment;
		}
		
		@Override
		public Dialog onCreateDialog(Bundle safedInstanceState) {
			int title = getArguments().getInt("title");
			final String[] items = getArguments().getStringArray("items");
			final int selectKind = getArguments().getInt("select_kind");
			selectedItem = items[0];
			
			AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
			builder.setTitle(title);
			builder.setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
			    public void onClick(DialogInterface dialog, int item) {
			    	selectedItem = items[item];
			    }
			})
			.setPositiveButton("OK", new DialogInterface.OnClickListener() {
	        	public void onClick(DialogInterface dialog, int whichButton) {
	        		MainActivity activity = (MainActivity)getActivity();
	        		if (selectKind == 0) {
	        			activity.onPhoneNumberSelect(selectedItem);
	        		} else {
	        			activity.onMailAddressSelect(selectedItem);
	        		}
	        	}
	        })
	        .setNegativeButton("Cancel", null);
			
			return builder.create();
		}
    }
}

activity_main.xml

以下レイアウトファイル

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

    <TableLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="名前" />
		</TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
            		     
            <EditText
		        android:id="@+id/name1"
		        android:layout_width="0dp"
		        android:layout_height="wrap_content"
		        android:layout_weight="1" />
            
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
            
            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="電話番号" />
    	
		</TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
            
            <EditText
		        android:id="@+id/phone_number"
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content"
		        android:layout_weight="1" />
            
        </TableRow>
	</TableLayout>
	
    <Button
        android:id="@+id/get_phone_number"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:text="電話番号の取得" />
    
	<TableLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="名前" />
		
		</TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
            
            <EditText
		        android:id="@+id/name2"
		        android:layout_width="0dp"
		        android:layout_height="wrap_content"
		        android:layout_weight="1" />
            
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
            
            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="メールアドレス" />

		</TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
            
            <EditText
		        android:id="@+id/mail_address"
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content"
		        android:layout_weight="1" />
            
        </TableRow>
        
	</TableLayout>

    <Button
        android:id="@+id/get_mail_address"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:text="メールアドレスの取得" />
    
</LinearLayout>

パーミッション

このコードを実行するには以下のパーミッションが必要

<uses-permission android:name="android.permission.READ_CONTACTS" />

実行

こんな感じ、選択した電話番号、メールアドレスをEditTextにセットする。

device-2014-01-26-133400device-2014-01-26-133444device-2014-01-26-133524

作成したサンプルプロジェクト
AddressBookSample

json形式のファイルの読み込みと作成をする

json形式のファイルの読み込みと作成の処理。

作成するファイル名は”sample.json”とし、保存先は「Environment.getExternalStorageDirectory()」
で取得したフォルダのルートとする。以下jsonファイルの中身。

{
    "Employee": [
        {
            "Age": 25, 
            "Name": "田中 一郎"
        }, 
        {
            "Age": 30, 
            "Name": "鈴木 次郎"
        }, 
        {
            "Age": 46, 
            "Name": "斉藤 三郎"
        }, 
        {
            "Age": 35, 
            "Name": "高橋 花子"
        }
    ]
}

jsonファイルの作成

以下コード

try {
	JSONObject jsonObject = new JSONObject();
	JSONArray jsonArary = new JSONArray();
	
	// jsonデータの作成
	JSONObject jsonOneData;
	jsonOneData = new JSONObject();
	jsonOneData.put("Name", "田中 一郎");
	jsonOneData.put("Age", 25);
	jsonArary.put(jsonOneData);

	jsonOneData = new JSONObject();
	jsonOneData.put("Name", "鈴木 次郎");
	jsonOneData.put("Age", 30);
	jsonArary.put(jsonOneData);
	
	jsonOneData = new JSONObject();
	jsonOneData.put("Name", "斉藤 三郎");
	jsonOneData.put("Age", 46);
	jsonArary.put(jsonOneData);
	
	jsonOneData = new JSONObject();
	jsonOneData.put("Name", "高橋 花子");
	jsonOneData.put("Age", 35);
	jsonArary.put(jsonOneData);
	
	jsonObject.put("Employee", jsonArary);
	
	// jsonファイル出力
	File file = new File(Environment.getExternalStorageDirectory() + "/" +  "sample.json");
	FileWriter filewriter;

	filewriter = new FileWriter(file);
	BufferedWriter bw = new BufferedWriter(filewriter);
	PrintWriter pw = new PrintWriter(bw);
	pw.write(jsonObject.toString());
	pw.close();
} catch (IOException e) {
	e.printStackTrace();
} catch (JSONException e) {
	e.printStackTrace();
}

jsonファイルの読み込み

以下コード

// ファイルの読み込み
InputStream input;
try {
	input = new FileInputStream(Environment.getExternalStorageDirectory() + "/" +  "sample.json");
	int size = input.available();
	byte[] buffer = new byte[size];
	input.read(buffer);
	input.close();
	
	// Json読み込み
	String json = new String(buffer);
	JSONObject jsonObject = new JSONObject(json);

	// データ追加
	JSONArray jsonArray = jsonObject.getJSONArray("Employee");
	for (int i = 0; i < jsonArray.length(); i++) {
		JSONObject jsonOneRecord = jsonArray.getJSONObject(i);
		Log.v("mytag", jsonOneRecord.getString("Name"));
		Log.v("mytag", String.valueOf(jsonOneRecord.getInt("Age")));
	}
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
} catch (JSONException e) {
	e.printStackTrace();
}

以下今回作成したすべてのソース

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		Button btButton1 = (Button)findViewById(R.id.button1);
		btButton1.setOnClickListener(new OnClickListener() {
        	public void onClick(View v) {
        		try {
	        		JSONObject jsonObject = new JSONObject();
	        		JSONArray jsonArary = new JSONArray();
	        		
	        		// jsonデータの作成
	        		JSONObject jsonOneData;
	        		jsonOneData = new JSONObject();
	        		jsonOneData.put("Name", "田中 一郎");
	        		jsonOneData.put("Age", 25);
	        		jsonArary.put(jsonOneData);

	        		jsonOneData = new JSONObject();
	        		jsonOneData.put("Name", "鈴木 次郎");
	        		jsonOneData.put("Age", 30);
	        		jsonArary.put(jsonOneData);
	        		
	        		jsonOneData = new JSONObject();
	        		jsonOneData.put("Name", "斉藤 三郎");
	        		jsonOneData.put("Age", 46);
	        		jsonArary.put(jsonOneData);
	        		
	        		jsonOneData = new JSONObject();
	        		jsonOneData.put("Name", "高橋 花子");
	        		jsonOneData.put("Age", 35);
	        		jsonArary.put(jsonOneData);
	        		
	        		jsonObject.put("Employee", jsonArary);
	        		
	        		// jsonファイル出力
	    			File file = new File(Environment.getExternalStorageDirectory() + "/" +  "sample.json");
	    			FileWriter filewriter;
				
					filewriter = new FileWriter(file);
					BufferedWriter bw = new BufferedWriter(filewriter);
	    			PrintWriter pw = new PrintWriter(bw);
	    			pw.write(jsonObject.toString());
	    			pw.close();
				} catch (IOException e) {
					e.printStackTrace();
				} catch (JSONException e) {
					e.printStackTrace();
				}
        	}
		});
		
		Button btButton2 = (Button)findViewById(R.id.button2);
		btButton2.setOnClickListener(new OnClickListener() {
        	public void onClick(View v) {
        		// ファイルの読み込み
        		InputStream input;
        		try {
        			input = new FileInputStream(Environment.getExternalStorageDirectory() + "/" +  "sample.json");
        			int size = input.available();
            		byte[] buffer = new byte[size];
            		input.read(buffer);
            		input.close();
            		
            		// Json読み込み
            		String json = new String(buffer);
            		JSONObject jsonObject = new JSONObject(json);

            		// データ追加
            		JSONArray jsonArray = jsonObject.getJSONArray("Employee");
            		for (int i = 0; i < jsonArray.length(); i++) {
            			JSONObject jsonOneRecord = jsonArray.getJSONObject(i);
            			Log.v("mytag", jsonOneRecord.getString("Name"));
            			Log.v("mytag", String.valueOf(jsonOneRecord.getInt("Age")));
            		}
        		} catch (FileNotFoundException e) {
        			e.printStackTrace();
        		} catch (IOException e) {
        			e.printStackTrace();
        		} catch (JSONException e) {
        			e.printStackTrace();
        		}
        	}
		});
	}
}

パーミッション

実行するにはパーミッションの設定が必要。以下の文をAndroidManifest.xmlに追加

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

その他、jsonファイルを扱うライブラリとかもあるみたい。

DragSortListViewを使ってみる

ListView上でドラッグ&ドロップでソートしたい。前まではリスト項目に↑↓のボタンを表示してソートするようにしてたんだけど、ドラッグ&ドロップの方が見た目もいいし、どうにか実装したいと思っていたら、素晴らしいライブラリを見つけた。「DragSortListView」。

ライブラリはGitHubにあって、GooglePlayからも動作確認用のアプリがダウンロードできる。
ダウンロードすると「demo」と「library」フォルダあり、それぞれ、「demo」がデモ用アプリ、「library」が実際使用するライブラリ。それぞれをEclipseにインポートする。取りあえずデモアプリのソースを見たり、その中のリソースを引っ張ってきたりして自分でサンプルを作成してみることにする。

1.サンプリアプリの作成

やりたいのは、今あるテーブルデータのソートなので、デモアプリを見るといろいろな機能があるが、ここではテーブルデータのソートを想定したものを作成する。ListFragmentのListViewに表示するレイアウトは、テーブルのキーになるIDを組み込んだリストを使用し、Activity側でなら並べ替えられたIDを取得してテーブルデータを更新するイメージで作成。

2..サンプルアプリにライブラリをインポート

作成したプロジェクトにDragSortListViewのライブラリをインポートする。
作成したプロジェクトを右クリックし「Properties」をクリック。
image003

「Android」を選択し、右下Library「Add」をクリック
image004

「library」を選択し「OK」をクリック。
image008

下のエラーが出た。
[2014-01-07 13:41:55 – DragSortListviewSample] Found 2 versions of android-support-v4.jar in the dependency list,



[2014-01-07 13:41:55 – DragSortListviewSample] Jar mismatch! Fix your dependencies

おそらく作成しようとしているサンプルアプリの「android-support-v4.jar」とDagSortListViewの「android-support-v4.jar」が違うので出ていると思われる。作成するアプリのlibフォルダにあるものの方が新しいので「library」フォルダのlibフォルダにあるものに上書きした。(これでいいのかはわかりません。)

3.プログラム

作成するプログラムは以下の2つ

  • DSLVFragment.java
  • MainActivity.java

DSLVFragment.javaはリストフラグメント。以下ソース。

import java.util.ArrayList;
import java.util.List;
import android.app.ListFragment;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
import android.os.Bundle;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.mobeta.android.dslv.DragSortListView;
import com.mobeta.android.dslv.DragSortController;

public class DSLVFragment extends ListFragment {
    private ArrayAdapter<ListItem> adapter;
    private ArrayList<ListItem> list;
    private DragSortListView mDslv;
    private DragSortController mController;

    private DragSortListView.DropListener onDrop = new DragSortListView.DropListener() {
        @Override
        public void drop(int from, int to) {
            if (from != to) {
            	ListItem item = adapter.getItem(from);
                adapter.remove(item);
                adapter.insert(item, to);
            }
        }
    };

    private DragSortListView.RemoveListener onRemove = new DragSortListView.RemoveListener() {
        @Override
        public void remove(int which) {
            adapter.remove(adapter.getItem(which));
        }
    };

    public DragSortController getController() {
        return mController;
    }

    /**
     * Called from DSLVFragment.onActivityCreated(). Override to
     * set a different adapter.
     */
    public void setListAdapter() {
    	list = new ArrayList<ListItem>();
    	list.add(new ListItem(1, "アイテム1"));
        list.add(new ListItem(2, "アイテム2"));
        list.add(new ListItem(3, "アイテム3"));
        list.add(new ListItem(4, "アイテム4"));
        list.add(new ListItem(5, "アイテム5"));
        list.add(new ListItem(6, "アイテム6"));
        list.add(new ListItem(7, "アイテム7"));
        list.add(new ListItem(8, "アイテム8"));
        list.add(new ListItem(9, "アイテム9"));
        list.add(new ListItem(10, "アイテム10"));
        list.add(new ListItem(11, "アイテム11"));
        list.add(new ListItem(12, "アイテム12"));
        list.add(new ListItem(13, "アイテム13"));
        list.add(new ListItem(14, "アイテム14"));
        list.add(new ListItem(15, "アイテム15"));

		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.list_item_handle_left, parent, false);
				holder = new ViewHolder();
				holder.ivDragHandler = (ImageView)convertView.findViewById(R.id.drag_handle);
				holder.tvItemName = (TextView)convertView.findViewById(R.id.text);
				convertView.setTag(holder);
			} else {
				holder = (ViewHolder)convertView.getTag();
			}
			final ListItem item = getItem(position);
			holder.tvItemName.setText(item.getItemName());

			return convertView;
		}
	}

    private class ViewHolder {
    	ImageView ivDragHandler;
		TextView tvItemName;
	}

    /**
     * Called in onCreateView. Override this to provide a custom
     * DragSortController.
     */
    public DragSortController buildController(DragSortListView dslv) {
        // defaults are
        //   dragStartMode = onDown
        //   removeMode = flingRight
        DragSortController controller = new DragSortController(dslv);
        controller.setDragHandleId(R.id.drag_handle);
        controller.setClickRemoveId(R.id.click_remove);
        controller.setRemoveEnabled(false);
        controller.setSortEnabled(true);
        controller.setDragInitMode(DragSortController.ON_DOWN);
        controller.setRemoveMode(DragSortController.FLING_REMOVE);

        return controller;
    }

    /** Called when the activity is first created. */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mDslv = (DragSortListView) inflater.inflate(R.layout.dslv_fragment_main, container, false);
        mController = buildController(mDslv);
        mDslv.setFloatViewManager(mController);
        mDslv.setOnTouchListener(mController);
        mDslv.setDragEnabled(true);

        return mDslv;
    }

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

        ListView lv = getListView();

        // リストクリック
        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                    long arg3) {
                String message = String.format("Clicked item %d", arg2);
                Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
            }
        });

        // リスト長押し
        lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2,
                    long arg3) {
                String message = String.format("Long-clicked item %d", arg2);
                Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
                return true;
            }
        });

        mDslv = (DragSortListView) getListView();
        mDslv.setDropListener(onDrop);
        mDslv.setRemoveListener(onRemove);

        setListAdapter();
    }

    public ArrayList<Integer> getItemIds() {
    	ArrayList<Integer> itemIds = new ArrayList<Integer>();
    	for (int i = 0; i < adapter.getCount(); i++) {
    		ListItem groupItem = adapter.getItem(i);
    		itemIds.add(groupItem.getItemId());
    	}

    	return itemIds;
    }

    private class ListItem {
    	private int itemId = 0;
    	private String itemName = "";

    	public ListItem() {
    	}

    	public ListItem(int itemId, String itemName) {
    		this.itemId = itemId;
    		this.itemName = itemName;
    	}

    	public void setItemId(int itemId) {
    		this.itemId = itemId;
    	}

    	public int getItemId() {
    		return this.itemId;
    	}

    	public void setItemName(String itemName) {
    		this.itemName = itemName;
    	}

    	public String getItemName() {
    		return this.itemName;
    	}
    }
}

MainActivity.javaはメインのアクティビティ。以下ソース。

import java.util.ArrayList;
import android.os.Bundle;
import android.app.Activity;
import android.app.FragmentManager;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;

public class MainActivity extends Activity {
	ArrayAdapter<String> adapter;
    private String mTag = "dslvTag";

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

	    // ソート用リストフラグメントの表示
	    getFragmentManager().beginTransaction()
	    	.add(R.id.fragment_container, new DSLVFragment(), mTag).commit();

	    // 並べ替えられたIDを取得
	    Button btGetId = (Button)this.findViewById(R.id.get_id);
	    btGetId.setOnClickListener(new OnClickListener() {
        	public void onClick(View v) {
        		FragmentManager fm = getFragmentManager();
        		DSLVFragment fragment = (DSLVFragment)fm.findFragmentByTag(mTag);
        		ArrayList<Integer> groupIds = fragment.getItemIds();
        		for (int i = 0; i < groupIds.size(); i++) {
        			Log.v("mytag", String.valueOf(groupIds.get(i)));
        		}
        	}
        });
	}

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

4.レイアウトファイル

  • activity_main.xml
  • dslv_fragment_main.xml
  • list_item_handle_left.xml

activity_main.xmlはメインのレイアウト。以下xmlファイル。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:tools="http://schemas.android.com/tools"
	xmlns:dslv="http://schemas.android.com/apk/res-auto"
	android:id="@+id/main_layout"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	tools:context=".MainActivity"
	android:orientation="vertical" >

	<FrameLayout
	    android:id="@+id/fragment_container"
	    android:layout_width="match_parent"
	    android:layout_height="0dp"
	    android:layout_weight="1" />

	<Button
	    style="?android:attr/buttonStyleSmall"
		android:layout_width="match_parent"
 		android:layout_height="wrap_content"
 		android:id="@+id/get_id"
 		android:text="ソートされたIDの取得" />

</LinearLayout>

dslv_fragment_main.xmlはリストフラグメント用のレイアウト。以下xmlファイル。
基本サンプルから引っ張ってきたものだが、そのままだとエラーになったので
「xmlns:dslv=”http://schemas.android.com/apk/res-auto”」の部分を修正している。

<?xml version="1.0" encoding="utf-8"?>
<com.mobeta.android.dslv.DragSortListView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:dslv="http://schemas.android.com/apk/res-auto"
    android:id="@android:id/list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="3dp"
    android:layout_margin="3dp"
    android:dividerHeight="2dp"
    dslv:drag_enabled="true"
    dslv:collapsed_height="2dp"
    dslv:drag_scroll_start="0.33"
    dslv:max_drag_scroll_speed="0.5"
    dslv:float_alpha="0.6"
    dslv:slide_shuffle_speed="0.3"
    dslv:track_drag_sort="false"
    dslv:use_default_controller="false" />

list_item_handle_left.xmlはリストフラグメントのアイテムレイアウト。以下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="@dimen/item_height"
	android:orientation="horizontal">

	<ImageView
		android:id="@id/drag_handle"
	  	android:background="@drawable/drag"
	  	android:layout_width="wrap_content"
	  	android:layout_height="@dimen/item_height"
	  	android:layout_weight="0" />

	<TextView
	  	android:id="@+id/text"
	  	android:layout_width="wrap_content"
	  	android:layout_height="@dimen/item_height"
	  	android:layout_weight="1"
	  	android:textAppearance="?android:attr/textAppearanceMedium"
	  	android:gravity="center_vertical"
	  	android:paddingLeft="8dp" />

</LinearLayout>

5.実行

こんな感じ、理解してない部分もあるが、やりたいことは出来てるのでこれでok。
device-2014-01-07-204403
ボタン押すとActivity側でソートされたIDを取得するので、これでソートの処理ができる。

作成したサンプルアプリ
DragSortListviewSample

Android4.1でCalendarViewの表示がおかしい

Android4.0(かな?)からCalandarViewが追加されたみたいなんだが。
なぜかAndroid4.1だと表示がおかしい。どうなるかというと、以下のようになる。
device-2014-01-04-204911
どう見ても見にくい!
最初は設定値をいじれば直るだろうと思ってたけど、いろいろやってもだめ。
どうもバグっぽいんだよなぁ。

ちなみにAndroid4.2で使ってみると、以下の表示
calendar_view
正常に表示される。ちなみにAndrod4.0の端末は持ってないけど、エミュレータで試したら上のように正常に表示される。4.1だけだめなんなんかなぁ?

ListViewでCheckBoxを使用したとき少しはまったのでメモ

ListViewでCheckBoxを使用したとき少しはまったのでメモ。
何が起きたかというと、チェックしてリストをスクロースしていったん非表示にして
表示させると、チェック状態が消えた。

こんな感じ、下の画面でリストアイテムをチェックして、元に戻るとチェック状態が消える。
list_sample

以下そうなったソース

// チェックボックスの状態のセット
if (item.groupSelected()) {
	holder.cbGroupSelect.setChecked(true);
} else {
	holder.cbGroupSelect.setChecked(false);
}

// チェックボックスのチェックイベントのセット
holder.cbGroupSelect.setOnCheckedChangeListener(new OnCheckedChangeListener() {
	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
		item.setGroupSelectedState(isChecked);
		Log.v("mytag", String.valueOf(isChecked));
	}
});

状態セットとイベントリスナーの順番を変えたら直った。
以下、大丈夫になったソース

// チェックボックスのチェックイベントリスナーのセット
holder.cbGroupSelect.setOnCheckedChangeListener(new OnCheckedChangeListener() {
	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
		item.setGroupSelectedState(isChecked);
		Log.v("mytag", String.valueOf(isChecked));
	}
});

// チェックボックスの状態のセット
if (item.groupSelected()) {
	holder.cbGroupSelect.setChecked(true);
} else {
	holder.cbGroupSelect.setChecked(false);
}