ã¦ã¼ã¶ãã½ã¼ãå¯è½ãªListViewãããããªããã«ãã¦ã¿ã
ãã¿å ã¯
ãã¡ã
ã¦ã¼ã¶ãã½ã¼ãå¯è½ãªListView http://d.hatena.ne.jp/vvakame/20100718#1279453854
id:vvakame ãããç´ æ´ãããã³ã¼ããæ¸ãã¦ããã®ã§ãåæã«æ¹å¤ãã¾ããããããªããã«ãã¦ã¿ã¾ããã
ããããªãã
å¤æ°åã¨ãã ãã¶ããã£ã¡ããã¾ããã
ãããã ãå¤ããã¤ããããããããå¤ãã¡ãã£ãï¼ãã¸ï¼
ã³ã¡ã³ãå°ãªãã¦ããããªãããéä¸ã§ãããã¾ããã
apk
Android1.6-2.2
HT-03A(Android1.6)ã§åä½ç¢ºèªãã¾ããã
DragonDropList.apk
使ãæ¹
- åæç¶æ ã ã¨æ®éã®ListViewã§ãã
- sort toggleãã§ãã¯ããã¯ã¹ããªã³ã«ããã¨ã½ã¼ãã¢ã¼ãã«å ¥ãã¾ãã
- è¦ç´ ã®å ¥ãæ¿ãã¯ç´æçã«åããã¯ãã
- ä¸ã®Ãå°ã«ããããããã¨è¦ç´ ãåé¤ããã¾ãã
- sort toggleãã§ãã¯ããã¯ã¹ããªãã«ããã¨é常ã®ListViewã«æ»ãã¾ãã
足ããªãã¨ãã
ã½ã¼ãä¸ã«ã¹ã¯ãã¼ã«ã§ããªãã®ã§ã©ãã«ãããããã©ãããæ¹æ³æãã¤ããªã
ã½ã¼ãç¨ã®ãã¿ã³ãæ¼ãã¨æ´ããã¨ãã§ããã¨ããé·æ¼ãããã¨æ´ããã¨ãã§ããã¨ã
ã¹ãã¼ããªæ¹æ³ãªãã§ãããã»ã»ã»ï¼
ã½ã¼ã¹
DragnDropActivity.java
package jp.tomorrowkey.android.dragondroplist; import java.util.ArrayList; import java.util.Arrays; import jp.tomorrowkey.android.dragondroplist.DragnDropListView.SortableAdapter; import android.app.Activity; import android.content.Context; import android.graphics.Color; 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.CheckBox; import android.widget.ImageView; import android.widget.TextView; public class DragnDropActivity extends Activity implements OnClickListener { private static String[] items = { "01.åæµ·é", "02.é森ç", "03.岩æç", "04.å®®åç", "05.ç§ç°ç", "06.山形ç", "07.ç¦å³¶ç", "08.è¨åç", "09.æ æ¨ç", "10.群馬ç", "11.å¼çç", "12.åèç", "13.æ±äº¬é½", "14.ç¥å¥å·ç", "15.æ°æ½ç", "16.å¯å±±ç", "17.ç³å·ç", "18.ç¦äºç", "19.山梨ç", "20.é·éç", "21.å²éç", "22.é岡ç", "23.æç¥ç", "24.ä¸éç", "25.æ»è³ç", "26.京é½åº", "27.大éªåº", "28.å µåº«ç", "29å¥è¯ç", "30.åæå±±ç", "31.é³¥åç", "32.å³¶æ ¹ç", "33.岡山ç", "34.åºå³¶ç", "35.å±±å£ç", "36.徳島ç", "37.é¦å·ç", "38.æåªç", "39.é«ç¥ç", "40.ç¦å²¡ç", "41.ä½è³ç", "42.é·å´ç", "43.çæ¬ç", "44.大åç", "45.å®®å´ç", "46.鹿å 島ç", "47.æ²ç¸ç" }; private static final int SELECTED_BG_COLOR = Color.argb(128, 255, 255, 255); private static final int HOVER_BG_COLOR = Color.argb(128, 255, 102, 0); private ArrayList<String> array; private StringArrayAdapter adapter = null; private DragnDropListView list; private ImageView imgRemoveTile; private CheckBox chkSort; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); array = new ArrayList<String>(Arrays.asList(items)); adapter = new StringArrayAdapter(this, array); list = (DragnDropListView) findViewById(R.id.list); list.setAdapter(adapter); chkSort = (CheckBox) findViewById(R.id.chkSort); chkSort.setOnClickListener(this); imgRemoveTile = (ImageView) findViewById(R.id.imgRemoveTile); list.setRemoveTile(imgRemoveTile); } @Override public void onClick(View v) { boolean sortable = chkSort.isChecked(); list.setSortMode(sortable); if (sortable) { imgRemoveTile.setVisibility(View.VISIBLE); } else { imgRemoveTile.setVisibility(View.GONE); } } class StringArrayAdapter extends ArrayAdapter<String> implements SortableAdapter { private ArrayList<String> list; private LayoutInflater inflater; private int selectedPosition = -1; private int hoverPosition = -1; public StringArrayAdapter(Context context, ArrayList<String> list) { super(context, R.layout.row, list); this.list = list; inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public View getView(int position, View convertView, ViewGroup parent) { View view = null; ViewHolder holder = null; if (convertView == null) { view = inflater.inflate(R.layout.row, null); holder = new ViewHolder(); holder.txtString = (TextView) view.findViewById(R.id.txtString); view.setTag(holder); } else { view = convertView; holder = (ViewHolder) view.getTag(); } if (selectedPosition == hoverPosition) { if (position == selectedPosition) { view.setBackgroundColor(HOVER_BG_COLOR); } else { view.setBackgroundResource(android.R.drawable.list_selector_background); } } else { if (position == selectedPosition) { view.setBackgroundColor(SELECTED_BG_COLOR); } else if (position == hoverPosition) { view.setBackgroundColor(HOVER_BG_COLOR); } else { view.setBackgroundResource(android.R.drawable.list_selector_background); } } holder.txtString.setText(list.get(position)); return view; } @Override public void setSelectedPosition(int position) { if (selectedPosition != position) { selectedPosition = position; notifyDataSetChanged(); } } @Override public void setHoverPosition(int position) { if (hoverPosition != position) { hoverPosition = position; notifyDataSetChanged(); } } } class ViewHolder { TextView txtString; } }
DragnDropListView.java
package jp.tomorrowkey.android.dragondroplist; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import android.widget.Adapter; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.ListView; public class DragnDropListView extends ListView { private static final String TAG = DragnDropListView.class.getSimpleName(); private static final boolean DEBUG = false; private static final int SCROLL_SPEED_FAST = 25; private static final int SCROLL_SPEED_SLOW = 8; private static final int MOVING_ITEM_BG_COLOR = Color.argb(128, 0, 0, 0); private static final int HOVER_REMOVE_ITEM_BG_COLOR = Color.argb(200, 255, 0, 0); private boolean sortMode = false; private DragListener mDrag = new DragListenerImpl(); private DropListener mDrop = new DropListenerImpl(); private RemoveListener mRemove = new RemoveListenerImpl(); public DragnDropListView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DragnDropListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } private SortableAdapter adapter; private Bitmap mDragBitmap = null; private ImageView mDragView = null; private WindowManager.LayoutParams mWindowParams = null; private int mFrom = -1; private View mRemoveTile = null; private Rect mRemoveHit = null; @Override public boolean onTouchEvent(MotionEvent event) { if (!sortMode) { return super.onTouchEvent(event); } int index = -1; final int x = (int) event.getX(); final int y = (int) event.getY(); int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { index = pointToIndex(event); if (index < 0) { return false; } mFrom = index; startDrag(); adapter.setSelectedPosition(index); return true; } else if (action == MotionEvent.ACTION_MOVE) { final int height = getHeight(); final int fastBound = height / 9; final int slowBound = height / 4; final int center = height / 2; int speed = 0; if (event.getEventTime() - event.getDownTime() < 500) { // 500ããªç§éã¯ã¹ã¯ãã¼ã«ãªã } else if (y < slowBound) { speed = y < fastBound ? -SCROLL_SPEED_FAST : -SCROLL_SPEED_SLOW; } else if (y > height - slowBound) { speed = y > height - fastBound ? SCROLL_SPEED_FAST : SCROLL_SPEED_SLOW; } if (DEBUG) { Log.d(TAG, "ACTION_MOVE y=" + y + ", height=" + height + ", fastBound=" + fastBound + ", slowBound=" + slowBound + ", center=" + center + ", speed=" + speed); } View v = null; if (speed != 0) { // 横æ¹åã¯ã¨ããããèããªã int centerPosition = pointToPosition(0, center); if (centerPosition == AdapterView.INVALID_POSITION) { centerPosition = pointToPosition(0, center + getDividerHeight() + 64); } v = getChildByIndex(centerPosition); if (v != null) { int pos = v.getTop(); setSelectionFromTop(centerPosition, pos - speed); } } if (mDragView != null) { if (mDragView.getHeight() < 0) { mDragView.setVisibility(View.INVISIBLE); } else { mDragView.setVisibility(View.VISIBLE); if (this.isHitRemoveTile(x, y)) { mDragView.setBackgroundColor(HOVER_REMOVE_ITEM_BG_COLOR); } else { mDragView.setBackgroundColor(MOVING_ITEM_BG_COLOR); } } mWindowParams.x = getLeft(); mWindowParams.y = getTop() + y; WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); wm.updateViewLayout(mDragView, mWindowParams); if (mDrag != null) { index = pointToIndex(event); mDrag.drag(mFrom, index); } adapter.setHoverPosition(index); return true; } } else if (action == MotionEvent.ACTION_UP) { if (isHitRemoveTile(x, y)) { // åé¤ã¤ã¡ã¼ã¸ã«ããããã¦ããå ´åãåé¤ãã if (mRemove != null) mRemove.remove(mFrom); } else { // åé¤ã¤ã¡ã¼ã¸ã«ããããã¦ããªããã°ãè¦ç´ ã®å ¥ãæ¿ãããã if (mDrop != null) { index = pointToIndex(event); mDrop.drop(mFrom, index); } } // ãã©ãã°ä¸ã®é ç®ã®è¡¨ç¤ºãåé¤ãã endDrag(); adapter.setHoverPosition(-1); adapter.setSelectedPosition(-1); return true; } else if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_OUTSIDE) { // ãã©ãã°ä¸ã®é ç®ã®è¡¨ç¤ºãåé¤ãã endDrag(); adapter.setHoverPosition(-1); adapter.setSelectedPosition(-1); return true; } else { Log.d(TAG, "Unknown event action=" + action); } return super.onTouchEvent(event); } /** * ãã©ãã°ãéå§ããã¨ãã«å¼ã³åºããã<br /> * ãã©ãã°ä¸ã®é ç®ã表示ãã */ private void startDrag() { WindowManager wm; View view = getChildByIndex(mFrom); final Bitmap.Config c = Bitmap.Config.ARGB_8888; mDragBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), c); Canvas canvas = new Canvas(); canvas.setBitmap(mDragBitmap); view.draw(canvas); if (mWindowParams == null) { mWindowParams = new WindowManager.LayoutParams(); mWindowParams.gravity = Gravity.TOP | Gravity.LEFT; mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT; mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; mWindowParams.format = PixelFormat.TRANSLUCENT; mWindowParams.windowAnimations = 0; mWindowParams.x = 0; mWindowParams.y = 0; } ImageView v = new ImageView(getContext()); v.setBackgroundColor(MOVING_ITEM_BG_COLOR); v.setImageBitmap(mDragBitmap); wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); if (mDragView != null) { wm.removeView(mDragView); } wm.addView(v, mWindowParams); mDragView = v; } /** * ãã©ãã°ã¢ã³ããããããçµäºããã¨ãã«å¼ã³åºããã<br /> * ãã©ãã°ä¸ã®é ç®ã®è¡¨ç¤ºãåé¤ãã */ private void endDrag() { if (mDragView == null) { return; } WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); wm.removeView(mDragView); mDragView = null; // ãªãµã¤ã¯ã«ããã¨ãã¾ã«æ»ã¬ãã©ã¿ã¤ãã³ã°åãããªã // Desireã§ããããht-03aã ã¨çºçããªã // mDragBitmap.recycle(); mDragBitmap = null; } /** * æå®ããã座æ¨ãåé¤ç»åã«è¢«ã£ã¦ãããè¿ã * * @param x * @param y * @return */ private boolean isHitRemoveTile(int x, int y) { if (mRemoveTile != null && mRemoveTile.getVisibility() == View.VISIBLE) { if (mRemoveHit == null) { mRemoveHit = new Rect(); } mRemoveTile.getHitRect(mRemoveHit); if (mRemoveHit.contains(x + getLeft(), y + getTop())) { return true; } else { return false; } } else { return false; } } /** * æå®ãããè¦ç´ çªå·ã®Viewãè¿ã<br /> * è¦ç´ çªå·ã¯ã½ã¼ã¹ã¨ãªãListã®è¦ç´ çªå·ãæå®ãã * * @param index * @return */ private View getChildByIndex(int index) { return getChildAt(index - getFirstVisiblePosition()); } /** * MotionEventããè¦ç´ çªå·ã«å¤æãã * * @param ev * @return */ private int pointToIndex(MotionEvent event) { return pointToIndex((int) event.getX(), (int) event.getY()); } /** * 座æ¨ããè¦ç´ çªå·ã«å¤æãã * * @param x * @param y * @return */ private int pointToIndex(int x, int y) { return (int) pointToPosition(x, y); } /** * åé¤ç»åã®è¨å® * * @param v */ public void setRemoveTile(View v) { mRemoveTile = v; } public void setOnDragListener(DragListener listener) { mDrag = listener; } public void setOnDropListener(DragListener listener) { mDrag = listener; } public void setOnRemoveListener(RemoveListener listener) { mRemove = listener; } public interface DragListener { public void drag(int from, int to); } public interface DropListener { public void drop(int from, int to); } public interface RemoveListener { public void remove(int which); } class DragListenerImpl implements DragListener { public void drag(int from, int to) { if (DEBUG) { Log.d(TAG, "DragListenerImpl drag event. from=" + from + ", to=" + to); } } } public class DropListenerImpl implements DropListener { @SuppressWarnings("unchecked") public void drop(int from, int to) { if (DEBUG) { Log.d(TAG, "DropListenerImpl drop event. from=" + from + ", to=" + to); } if (from == to || from < 0 || to < 0) { return; } Adapter adapter = getAdapter(); if (adapter != null && adapter instanceof ArrayAdapter) { ArrayAdapter arrayAdapter = (ArrayAdapter) adapter; Object item = adapter.getItem(from); arrayAdapter.remove(item); arrayAdapter.insert(item, to); } } } public class RemoveListenerImpl implements RemoveListener { @SuppressWarnings("unchecked") public void remove(int which) { if (DEBUG) { Log.d(TAG, "RemoveListenerImpl remove event. which=" + which); } if (which < 0) { return; } Adapter adapter = getAdapter(); if (adapter != null && adapter instanceof ArrayAdapter) { ArrayAdapter arrayAdapter = (ArrayAdapter) adapter; Object item = adapter.getItem(which); arrayAdapter.remove(item); } } } /** * 並ã³æ¿ããããããè¨å®ãã * * @param sortMode */ public void setSortMode(boolean sortMode) { this.sortMode = sortMode; } /** * 並ã³æ¿ããããããè¿ã * * @return */ public boolean isSortMode() { return sortMode; } /** * ListViewã«Adapterãè¨å®ãã<br /> * Sortableãå®è£ ããAdapter以å¤ãåãä»ãã¾ãã * * @param adapter */ @Override public void setAdapter(ListAdapter adapter) { if (adapter instanceof SortableAdapter) { this.adapter = (SortableAdapter) adapter; super.setAdapter(adapter); } else { throw new RuntimeException("Adapterã¯Sortableãå®è£ ããå¿ è¦ãããã¾ã"); } } interface SortableAdapter { void setSelectedPosition(int position); void setHoverPosition(int position); } }
main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <CheckBox android:text="sort toggle" android:id="@+id/chkSort" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/imgRemoveTile" android:src="@drawable/remove_tile" android:background="#80FF0000" android:scaleType="center" android:visibility="gone" android:layout_margin="2dip" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <jp.tomorrowkey.android.dragondroplist.DragnDropListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout>
row.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/txtString" android:textSize="24dip" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
remove_tile.png
質åã¨ããã£ãã
twitterã§çãããï¼ï¼