1.记得加一个震动的权限:
<!-- 震动权限 --> <uses-permission android:name="android.permission.VIBRATE"/>2. MainActivity
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { private MyGridView mOtherGv; private DragGridView mUserGv; private List<String> mUserList = new ArrayList<>(); private List<String> mOtherList = new ArrayList<>(); private OtherAdapter mOtherAdapter; private DragAdapter mUserAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } public void initView() { mUserGv = (DragGridView) findViewById(R.id.userGridView); mOtherGv = (MyGridView) findViewById(R.id.otherGridView); mUserList.add("推荐"); mUserList.add("热点"); mUserList.add("上海"); mUserList.add("时尚"); mUserList.add("科技"); mUserList.add("体育"); mUserList.add("军事"); mUserList.add("财经"); mUserList.add("网络"); mOtherList.add("汽车"); mOtherList.add("房产"); mOtherList.add("社会"); mOtherList.add("情感"); mOtherList.add("女人"); mOtherList.add("旅游"); mOtherList.add("健康"); mOtherList.add("美女"); mOtherList.add("游戏"); mOtherList.add("数码"); mOtherList.add("娱乐"); mOtherList.add("探索"); mUserAdapter = new DragAdapter(this, mUserList,true); mOtherAdapter = new OtherAdapter(this, mOtherList,false); mUserGv.setAdapter(mUserAdapter); mOtherGv.setAdapter(mOtherAdapter); mUserGv.setOnItemClickListener(this); mOtherGv.setOnItemClickListener(this);
/* mOtherGv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) { new AlertDialog.Builder(MainActivity.this) .setIcon(R.mipmap.ic_launcher) .setTitle("网络选择") .setSingleChoiceItems(new String[]{"wifi", "手机流量"}, 0, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (which == 1) { setNetworkMethod(MainActivity.this); dialog.dismiss(); } else { // updateVersion("http://172.18.47.36/download/banner.apk"); checkVerson(); } } }) .create().show(); return false; } });*/}
/* private void checkVerson() { int versionCode = VersionUtil.getVersoinCode(this); RequestParams params = new RequestParams(url); params.addQueryStringParameter("version", String.valueOf(versionCode)); x.http().get(params, new Callback.CommonCallback<String>() { @Override public void onSuccess(String result) { Gson gson = new Gson(); Type type = new TypeToken<MessageBean<ZHIj>>() { }.getType(); MessageBean<ZHIj> messageBean = gson.fromJson(result, type); if (messageBean.isSuccess()) { final ZHIj version = messageBean.getResult(); // 有更新 if (version.isHasNewVersion()) { // 强制更新 if (version.isMustUpdate()) { new AlertDialog.Builder(MainActivity.this) .setTitle("版本更新") .setMessage("升级到最新版本") .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { updateVersion(version.getUrl()); dialog.dismiss(); } }) .setNegativeButton("下次再说", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }) // 不可取消 .setCancelable(false) .create().show(); } } } } @Override public void onError(Throwable ex, boolean isOnCallback) { } @Override public void onCancelled(CancelledException cex) { } @Override public void onFinished() { } }); } // private void updateVersion(String url) { // downLoad = downLoad + System.currentTimeMillis() + ".apk"; // RequestParams params = new RequestParams(url); // params.setSaveFilePath(downLoad); // x.http().get(params, new Callback.ProgressCallback<File>() { // @Override // public void onSuccess(File result) { // if (progressDialog.isShowing()) { // progressDialog.dismiss(); // } // installApk(result); // } // // @Override // public void onError(Throwable ex, boolean isOnCallback) { // if (progressDialog.isShowing()) { // progressDialog.dismiss(); // } // Toast.makeText(MainActivity.this, "下载失败", Toast.LENGTH_SHORT).show(); // } // // @Override // public void onCancelled(CancelledException cex) { // // } // // @Override // public void onFinished() { // // } // // @Override // public void onWaiting() { // // } // // @Override // public void onStarted() { // // } // // @Override // public void onLoading(long total, long current, boolean isDownloading) { // if (isDownloading) { // progressDialog.setMessage("正在下载..."); // progressDialog.show(); // progressDialog.setMax((int) total); // progressDialog.setProgress((int) current); // } // } // }); // } *//** * 安装apk * * @param file *//* private void installApk(File file) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.addCategory("android.intent.category.DEFAULT"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); startActivity(intent); android.os.Process.killProcess(android.os.Process.myPid()); } public static void setNetworkMethod(final Context context) { //提示对话框 AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle("网络设置提示").setMessage("网络连接不可用,是否进行设置?").setPositiveButton("设置", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub Intent intent = null; //判断手机系统的版本 即API大于10 就是3.0或以上版本 if (android.os.Build.VERSION.SDK_INT > 10) { intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS); } else { intent = new Intent(); ComponentName component = new ComponentName("com.android.settings", "com.android.settings.WirelessSettings"); intent.setComponent(component); intent.setAction("android.intent.action.VIEW"); } context.startActivity(intent); } }).setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub dialog.dismiss(); } }).show(); } */
/** *获取点击的Item的对应View, *因为点击的Item已经有了自己归属的父容器MyGridView,所有我们要是有一个ImageView来代替Item移动 * @param view * @return */ private ImageView getView(View view) { view.destroyDrawingCache(); view.setDrawingCacheEnabled(true); Bitmap cache = Bitmap.createBitmap(view.getDrawingCache()); view.setDrawingCacheEnabled(false); ImageView iv = new ImageView(this); iv.setImageBitmap(cache); return iv; } /** * 获取移动的VIEW,放入对应ViewGroup布局容器 * @param viewGroup * @param view * @param initLocation * @return */ private View getMoveView(ViewGroup viewGroup, View view, int[] initLocation) { int x = initLocation[0]; int y = initLocation[1]; viewGroup.addView(view); LinearLayout.LayoutParams mLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); mLayoutParams.leftMargin = x; mLayoutParams.topMargin = y; view.setLayoutParams(mLayoutParams); return view; } /** * 创建移动的ITEM对应的ViewGroup布局容器 * 用于存放我们移动的View */ private ViewGroup getMoveViewGroup() { //window中最顶层的view ViewGroup moveViewGroup = (ViewGroup) getWindow().getDecorView(); LinearLayout moveLinearLayout = new LinearLayout(this); moveLinearLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); moveViewGroup.addView(moveLinearLayout); return moveLinearLayout; } /** * 点击ITEM移动动画 * * @param moveView * @param startLocation * @param endLocation * @param moveChannel * @param clickGridView */ private void MoveAnim(View moveView, int[] startLocation, int[] endLocation, final String moveChannel, final GridView clickGridView, final boolean isUser) { int[] initLocation = new int[2]; //获取传递过来的VIEW的坐标 moveView.getLocationInWindow(initLocation); //得到要移动的VIEW,并放入对应的容器中 final ViewGroup moveViewGroup = getMoveViewGroup(); final View mMoveView = getMoveView(moveViewGroup, moveView, initLocation); //创建移动动画 TranslateAnimation moveAnimation = new TranslateAnimation( startLocation[0], endLocation[0], startLocation[1], endLocation[1]); moveAnimation.setDuration(300L);//动画时间 //动画配置 AnimationSet moveAnimationSet = new AnimationSet(true); moveAnimationSet.setFillAfter(false);//动画效果执行完毕后,View对象不保留在终止的位置 moveAnimationSet.addAnimation(moveAnimation); mMoveView.startAnimation(moveAnimationSet); moveAnimationSet.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { moveViewGroup.removeView(mMoveView); // 判断点击的是DragGrid还是OtherGridView if (isUser) { mOtherAdapter.setVisible(true); mOtherAdapter.notifyDataSetChanged(); mUserAdapter.remove(); } else { mUserAdapter.setVisible(true); mUserAdapter.notifyDataSetChanged(); mOtherAdapter.remove(); } } }); } @Override public void onItemClick(AdapterView<?> parent, View view, final int position, long id) { switch (parent.getId()) { case R.id.userGridView: //position为 0,1 的不可以进行任何操作 if (position != 0 && position != 1) { final ImageView moveImageView = getView(view); if (moveImageView != null) { TextView newTextView = (TextView) view.findViewById(R.id.text_item); final int[] startLocation = new int[2]; newTextView.getLocationInWindow(startLocation); final String channel = ((DragAdapter) parent.getAdapter()).getItem(position);//获取点击的频道内容 mOtherAdapter.setVisible(false); //添加到最后一个 mOtherAdapter.addItem(channel); new Handler().postDelayed(new Runnable() { public void run() { try { int[] endLocation = new int[2]; //获取终点的坐标 mOtherGv.getChildAt(mOtherGv.getLastVisiblePosition()).getLocationInWindow(endLocation); MoveAnim(moveImageView, startLocation, endLocation, channel, mUserGv, true); mUserAdapter.setRemove(position); } catch (Exception localException) { } } }, 50L); } } break; case R.id.otherGridView: final ImageView moveImageView = getView(view); if (moveImageView != null) { TextView newTextView = (TextView) view.findViewById(R.id.text_item); final int[] startLocation = new int[2]; newTextView.getLocationInWindow(startLocation); final String channel = ((OtherAdapter) parent.getAdapter()).getItem(position); mUserAdapter.setVisible(false); //添加到最后一个 mUserAdapter.addItem(channel); new Handler().postDelayed(new Runnable() { public void run() { try { int[] endLocation = new int[2]; //获取终点的坐标 mUserGv.getChildAt(mUserGv.getLastVisiblePosition()).getLocationInWindow(endLocation); MoveAnim(moveImageView, startLocation, endLocation, channel, mOtherGv,false); mOtherAdapter.setRemove(position); } catch (Exception localException) { } } }, 50L); } break; default: break; } } }
MainActivity 的布局文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" > <ScrollView android:layout_width="fill_parent" android:layout_height="fill_parent" > <LinearLayout android:id="@+id/subscribe_main_layout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingBottom="14.0dip" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="10.0dip" android:layout_marginTop="14.0dip" android:gravity="bottom" android:orientation="horizontal" > <TextView android:id="@+id/my_category_tip_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="13sp" android:text="我的频道" /> </LinearLayout> <View android:id="@+id/seperate_line" android:layout_width="match_parent" android:layout_marginTop="10dp" android:layout_height="0.5dp" android:layout_marginBottom="14.0dip" android:background="@color/subscribe_item_drag_stroke" /> <view.DragGridView android:id="@+id/userGridView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="14dip" android:layout_marginRight="14dip" android:gravity="center" android:horizontalSpacing="14dip" android:listSelector="@android:color/transparent" android:numColumns="4" android:scrollbars="vertical" android:stretchMode="columnWidth" android:verticalSpacing="14.0px" /> <View android:id="@+id/seperate_line2" android:layout_marginTop="10dp" android:layout_width="match_parent" android:layout_height="0.5dp" android:background="@color/subscribe_item_drag_stroke"/> <TextView android:id="@+id/more_category_text" android:layout_marginBottom="14.0dip" android:layout_width="wrap_content" android:layout_marginTop="10dp" android:layout_height="wrap_content" android:textSize="13sp" android:layout_marginLeft="10.0dip" android:text="更多频道" /> <view.MyGridView android:id="@+id/otherGridView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="14dip" android:layout_marginRight="14dip" android:gravity="center" android:horizontalSpacing="14dip" android:listSelector="@android:color/transparent" android:numColumns="4" android:scrollbars="vertical" android:stretchMode="columnWidth" android:verticalSpacing="14.0px" /> </LinearLayout> </ScrollView> </RelativeLayout>需要颜色的种类在values下的colors.xml文件中需要配置:
<item name="subscribe_item_text_color_normal" type="color">@color/default_text</item> <color name="subscribe_item_text_color_pressed">#ffb9b9b9</color> <color name="default_text">#ff454545</color> <color name="subscribe_item_text_color_pressed_night">#ff303030</color> <color name="subscribe_item_focused_stroke">#ffd9d9d9</color> <color name="subscribe_item_drag_stroke">#ffd2d2d2</color> <color name="subscribe_item_drag_bg">#fff5f5f5</color> <color name="subscribe_item_drag_stroke_night">#ff464646</color> <color name="subscribe_item_drag_bg_night">#ff252525</color> <color name="subscribe_item_selected_bg">#ffffffff</color> <color name="subscribe_item_selected_stroke">#ffcc3131</color> <color name="subscribe_item_disabled_bg">#ffefefef</color> <color name="subscribe_item_disabled_stroke">#ffd9d9d9</color> <color name="subscribe_item_pressed_bg">#fff9f9f9</color> <color name="subscribe_item_pressed_stroke">#ffcdcdcd</color> <color name="subscribe_item_normal_bg">#fff5f5f5</color> <color name="subscribe_item_normal_stroke">#ffcdcdcd</color> <color name="subscribe_item_focused_bg_night">#ff252525</color> <color name="subscribe_item_focused_stroke_night">#ff464646</color> <color name="subscribe_item_selected_bg_night">#ff252525</color> <color name="subscribe_item_selected_stroke_night">#ffbc494d</color> <color name="subscribe_item_disabled_bg_night">#ff2b2b2b</color>两个适配器:DragAdapter 和 OtherAdapter
public class DragAdapter extends BaseAdapter { /** TAG*/ private final static String TAG = "DragAdapter"; /** 是否显示底部的ITEM */ private boolean isItemShow = false; private Context context; /** 控制的postion */ private int holdPosition; /** 是否改变 */ private boolean isChanged = false; /** 列表数据是否改变 */ private boolean isListChanged = false; /** 是否可见 */ boolean isVisible = true; /** 可以拖动的列表(即用户选择的频道列表) */ public List<String> channelList; /** TextView 频道内容 */ private TextView item_text; /** 要删除的position */ public int remove_position = -1; /** 是否是用户频道 */ private boolean isUser = false; public DragAdapter(Context context, List<String> channelList,boolean isUser) { this.context = context; this.channelList = channelList; this.isUser = isUser; } @Override public int getCount() { // TODO Auto-generated method stub return channelList == null ? 0 : channelList.size(); } @Override public String getItem(int position) { // TODO Auto-generated method stub if (channelList != null && channelList.size() != 0) { return channelList.get(position); } return null; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = LayoutInflater.from(context).inflate(R.layout.adapter_mygridview_item, null); item_text = (TextView) view.findViewById(R.id.text_item); String channel = getItem(position); item_text.setText(channel); if(isUser){ if ((position == 0) || (position == 1)){ item_text.setEnabled(false); } } if (isChanged && (position == holdPosition) && !isItemShow) { item_text.setText(""); item_text.setSelected(true); item_text.setEnabled(true); isChanged = false; } if (!isVisible && (position == -1 + channelList.size())) { item_text.setText(""); item_text.setSelected(true); item_text.setEnabled(true); } if(remove_position == position){ item_text.setText(""); } return view; } /** 添加频道列表 */ public void addItem(String channel) { channelList.add(channel); isListChanged = true; notifyDataSetChanged(); } /** 拖动变更频道排序 */ public void exchange(int dragPostion, int dropPostion) { holdPosition = dropPostion; String dragItem = getItem(dragPostion); Log.d(TAG, "startPostion=" + dragPostion + ";endPosition=" + dropPostion); if (dragPostion < dropPostion) { channelList.add(dropPostion + 1, dragItem); channelList.remove(dragPostion); } else { channelList.add(dropPostion, dragItem); channelList.remove(dragPostion + 1); } isChanged = true; isListChanged = true; notifyDataSetChanged(); } /** 获取频道列表 */ public List<String> getChannnelLst() { return channelList; } /** 设置删除的position */ public void setRemove(int position) { remove_position = position; notifyDataSetChanged(); } /** 删除频道列表 */ public void remove() { channelList.remove(remove_position); remove_position = -1; isListChanged = true; notifyDataSetChanged(); } /** 设置频道列表 */ public void setListDate(List<String> list) { channelList = list; } /** 获取是否可见 */ public boolean isVisible() { return isVisible; } /** 排序是否发生改变 */ public boolean isListChanged() { return isListChanged; } /** 设置是否可见 */ public void setVisible(boolean visible) { isVisible = visible; } /** 显示放下的ITEM */ public void setShowDropItem(boolean show) { isItemShow = show; } }public class OtherAdapter extends BaseAdapter { private Context context; public List<String> channelList; private TextView item_text; /** 是否可见 在移动动画完毕之前不可见,动画完毕后可见*/ boolean isVisible = true; /** 要删除的position */ public int remove_position = -1; /** 是否是用户频道 */ private boolean isUser = false; public OtherAdapter(Context context, List<String> channelList ,boolean isUser) { this.context = context; this.channelList = channelList; this.isUser = isUser; } @Override public int getCount() { return channelList == null ? 0 : channelList.size(); } @Override public String getItem(int position) { if (channelList != null && channelList.size() != 0) { return channelList.get(position); } return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = LayoutInflater.from(context).inflate(R.layout.adapter_mygridview_item, null); item_text = (TextView) view.findViewById(R.id.text_item); String channel = getItem(position); item_text.setText(channel); if(isUser){ if ((position == 0) || (position == 1)){ item_text.setEnabled(false); } } if (!isVisible && (position == -1 + channelList.size())){ item_text.setText(""); item_text.setSelected(true); item_text.setEnabled(true); } if(remove_position == position){ item_text.setText(""); } return view; } /** 获取频道列表 */ public List<String> getChannnelLst() { return channelList; } /** 添加频道列表 */ public void addItem(String channel) { channelList.add(channel); notifyDataSetChanged(); } /** 设置删除的position */ public void setRemove(int position) { remove_position = position; notifyDataSetChanged(); // notifyDataSetChanged(); } /** 删除频道列表 */ public void remove() { channelList.remove(remove_position); remove_position = -1; notifyDataSetChanged(); } /** 设置频道列表 */ public void setListDate(List<String> list) { channelList = list; } /** 获取是否可见 */ public boolean isVisible() { return isVisible; } /** 设置是否可见 */ public void setVisible(boolean visible) { isVisible = visible; } }适配器需要的布局:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rl_subscribe" android:layout_width="wrap_content" android:layout_height="wrap_content" android:minHeight="38.0dip" android:minWidth="72.0dip" > <TextView android:id="@+id/text_item" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="@drawable/subscribe_item_bg" android:gravity="center" android:minHeight="38.0dip" android:minWidth="72.0dip" android:textColor="@color/subscribe_item_text_color" android:textSize="14.0sp" /> <!-- android:layout_margin="5dip" --> <ImageView android:id="@+id/icon_new" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" /> </RelativeLayout>需要在res下建一个color文件夹下有一个subscribe_item_text_color.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" android:color="@color/subscribe_item_selected_stroke" /> <item android:state_pressed="true" android:color="@color/subscribe_item_text_color_pressed" /> <item android:color="@color/subscribe_item_text_color_normal" /> </selector>在drawable下建立一个subscribe_item_bg.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="true" android:state_selected="true"> <layer-list> <item> <shape> <stroke android:width="1.0dip" android:color="@color/subscribe_item_drag_stroke" android:dashWidth="4.0dip" android:dashGap="2.0dip" /> <solid android:color="@color/subscribe_item_drag_bg" /> </shape> </item> </layer-list> </item> <item android:state_selected="true"> <shape> <stroke android:width="1.0dip" android:color="@color/subscribe_item_selected_stroke" /> <solid android:color="@color/subscribe_item_selected_bg" /> </shape> </item> <item android:state_enabled="false"> <shape> <stroke android:width="0.5dip" android:color="@color/subscribe_item_disabled_stroke" /> <solid android:color="@color/subscribe_item_disabled_bg" /> </shape> </item> <item android:state_pressed="true"> <shape> <stroke android:width="0.5dip" android:color="@color/subscribe_item_pressed_stroke" /> <solid android:color="@color/subscribe_item_pressed_bg" /> </shape> </item> <item> <shape> <stroke android:width="0.5dip" android:color="@color/subscribe_item_normal_stroke" /> <solid android:color="@color/subscribe_item_normal_bg" /> </shape> </item> </selector>
3。创建两个自定义view DragGridView 和MyGridView
public class DragGridView extends GridView{ /** 点击时候的X位置 */ public int downX; /** 点击时候的Y位置 */ public int downY; /** 点击时候对应整个界面的X位置 */ public int windowX; /** 点击时候对应整个界面的Y位置 */ public int windowY; /** VIEW相对自己的X */ private int win_view_x; /**VIEW相对自己的Y*/ private int win_view_y; /** 长按时候对应postion */ public int dragPosition; /** Up后对应的ITEM的Position */ private int dropPosition; /** 开始拖动的ITEM的Position*/ private int startPosition; /** item高 */ private int itemHeight; /** item宽 */ private int itemWidth; /** 拖动的时候对应ITEM的VIEW */ private View dragImageView = null; /** 长按的时候ITEM的VIEW*/ private ViewGroup dragItemView = null; /** WindowManager管理器 */ private WindowManager windowManager = null; /** */ private WindowManager.LayoutParams windowParams = null; /** item总量*/ private int itemTotalCount; /** 一行的ITEM数量*/ private int nColumns = 4; /** 行数 */ private int nRows; /** 剩余部分 */ private int Remainder; /** 是否在移动 */ private boolean isMoving = false; /** */ private int holdPosition; /** 拖动的时候放大的倍数 */ private double dragScale = 1.2D; /** 震动器 */ private Vibrator mVibrator; /** 每个ITEM之间的水平间距 */ private int mHorizontalSpacing = 15; /** 每个ITEM之间的竖直间距 */ private int mVerticalSpacing = 15; /** 移动时候最后个动画的ID */ private String LastAnimationID; public DragGridView(Context context) { super(context); init(context); } public DragGridView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } public DragGridView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } /** * dip转为 px */ public int dip2px(Context context, float dipValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dipValue * scale + 0.5f); } public void init(Context context){ mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); //将布局文件中设置的间距dip转为px mHorizontalSpacing = dip2px(context, mHorizontalSpacing); } /** 在ScrollView内,所以要进行计算高度 */ @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { downX = (int) ev.getX(); downY = (int) ev.getY(); windowX = (int) ev.getX(); windowY = (int) ev.getY(); setOnItemClickListener(ev); } return super.dispatchTouchEvent(ev); } /** 停止拖动 ,释放并初始化 */ private void stopDrag() { if (dragImageView != null) { windowManager.removeView(dragImageView); dragImageView = null; } } /** 在拖动的情况更新View的位置 */ private void onDrag(int x, int y , int rawx , int rawy) { if (dragImageView != null) { windowParams.alpha = 0.6f; windowParams.x = rawx - win_view_x; windowParams.y = rawy - win_view_y; windowManager.updateViewLayout(dragImageView, windowParams); } } /** *创建窗口对象、添加我们要移动的View * @param dragBitmap * @param x * @param y */ public void startDrag(Bitmap dragBitmap, int x, int y) { stopDrag(); windowParams = new WindowManager.LayoutParams();// 获取WINDOW界面的 //Gravity.TOP|Gravity.LEFT;这个必须加 windowParams.gravity = Gravity.TOP | Gravity.LEFT; //得到要移动的View左上角相对于屏幕的坐标 windowParams.x = x - win_view_x; windowParams.y = y - win_view_y; //设置拖拽item的宽和高 windowParams.width = (int) (dragScale * dragBitmap.getWidth());// 放大dragScale倍,可以设置拖动后的倍数 windowParams.height = (int) (dragScale * dragBitmap.getHeight());// 放大dragScale倍,可以设置拖动后的倍数 this.windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; this.windowParams.format = PixelFormat.TRANSLUCENT; this.windowParams.windowAnimations = 0; ImageView iv = new ImageView(getContext()); iv.setImageBitmap(dragBitmap); windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);// "window" windowManager.addView(iv, windowParams); dragImageView = iv; } /** 隐藏 放下 的ITEM*/ private void hideDropItem() { ((DragAdapter) getAdapter()).setShowDropItem(false); } /** 在松手下放的情况,更新界面 */ private void onDrop(int x, int y) { // 根据拖动到的x,y坐标获取拖动位置下方的ITEM对应的POSTION int tempPostion = pointToPosition(x, y); // if (tempPostion != AdapterView.INVALID_POSITION) { dropPosition = tempPostion; DragAdapter mDragAdapter = (DragAdapter) getAdapter(); //显示刚拖动的ITEM mDragAdapter.setShowDropItem(true); //刷新适配器,让对应的ITEM显示 mDragAdapter.notifyDataSetChanged(); // } } /** * 长按点击监听 * @param ev */ public void setOnItemClickListener(final MotionEvent ev) { setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { int x = (int) ev.getX();// 长按事件的X位置 int y = (int) ev.getY();// 长按事件的y位置 startPosition = position;// 第一次点击的postion dragPosition = position; if (startPosition <= 1) {//前2个默认不点击、可以设置 return false; } ViewGroup dragViewGroup = (ViewGroup) getChildAt(dragPosition - getFirstVisiblePosition()); TextView dragTextView = (TextView)dragViewGroup.findViewById(R.id.text_item); dragTextView.setSelected(true); dragTextView.setEnabled(false); itemHeight = dragViewGroup.getHeight(); itemWidth = dragViewGroup.getWidth(); itemTotalCount = DragGridView.this.getCount(); // 如果特殊的这个不等于拖动的那个,并且不等于-1 if (dragPosition != AdapterView.INVALID_POSITION) { // 释放的资源使用的绘图缓存。如果你调用buildDrawingCache()手动没有调用setDrawingCacheEnabled(真正的),你应该清理缓存使用这种方法。 win_view_x = windowX - dragViewGroup.getLeft();//VIEW相对自己的X,半斤 win_view_y = windowY - dragViewGroup.getTop();//VIEW相对自己的y,半斤 dragItemView = dragViewGroup; dragViewGroup.destroyDrawingCache(); dragViewGroup.setDrawingCacheEnabled(true); Bitmap dragBitmap = Bitmap.createBitmap(dragViewGroup.getDrawingCache()); mVibrator.vibrate(50);//设置震动时间 startDrag(dragBitmap, (int)ev.getRawX(), (int)ev.getRawY()); hideDropItem(); dragViewGroup.setVisibility(View.INVISIBLE); isMoving = false; return true; } return false; } }); } @Override public boolean onTouchEvent(MotionEvent ev) { if (dragImageView != null && dragPosition != AdapterView.INVALID_POSITION) { // 移动时候的对应x,y位置 int x = (int) ev.getX(); int y = (int) ev.getY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: downX = (int) ev.getX(); windowX = (int) ev.getX(); downY = (int) ev.getY(); windowY = (int) ev.getY(); break; case MotionEvent.ACTION_MOVE: onDrag(x, y ,(int) ev.getRawX() , (int) ev.getRawY()); if (!isMoving){ OnMove(x, y); } if (pointToPosition(x, y) != AdapterView.INVALID_POSITION){ break; } break; case MotionEvent.ACTION_UP: stopDrag(); onDrop(x, y); requestDisallowInterceptTouchEvent(false); break; default: break; } } return super.onTouchEvent(ev); } /** 移动的时候触发,移动所有改变的Item*/ public void OnMove(int x, int y) { // 拖动的VIEW下方的POSTION int dPosition = pointToPosition(x, y); // 判断下方的POSTION是否是最开始2个不能拖动的 if (dPosition > 1) { if ((dPosition == -1) || (dPosition == dragPosition)){ return; } dropPosition = dPosition; if (dragPosition != startPosition){ dragPosition = startPosition; } int movecount; //拖动的=开始拖的,并且 拖动的 不等于放下的 if ((dragPosition == startPosition) || (dragPosition != dropPosition)){ //移需要移动的动ITEM数量 movecount = dropPosition - dragPosition; }else{ //移需要移动的动ITEM数量为0 movecount = 0; } if(movecount == 0){ return; } int movecount_abs = Math.abs(movecount); if (dPosition != dragPosition) { //dragGroup设置为不可见 ViewGroup dragGroup = (ViewGroup) getChildAt(dragPosition); dragGroup.setVisibility(View.INVISIBLE); float to_x = 1;//移动的X偏移量 float to_y;// 移动的Y偏移量 //x_vlaue移动的距离百分比(相对于自己长度的百分比) float x_vlaue = ((float) mHorizontalSpacing / (float) itemWidth) + 1.0f; //y_vlaue移动的距离百分比(相对于自己宽度的百分比) float y_vlaue = ((float) mVerticalSpacing / (float) itemHeight) + 1.0f; Log.d("x_vlaue", "x_vlaue = " + x_vlaue); for (int i = 0; i < movecount_abs; i++) { to_x = x_vlaue; to_y = y_vlaue; //向右 if (movecount > 0) { // 判断是不是同一行的 holdPosition = dragPosition + i + 1; if (dragPosition / nColumns == holdPosition / nColumns) { to_x = - x_vlaue; to_y = 0; } else if (holdPosition % 4 == 0) { to_x = 3 * x_vlaue; to_y = - y_vlaue; } else { to_x = - x_vlaue; to_y = 0; } }else{ //向左,下移到上,右移到左 holdPosition = dragPosition - i - 1; if (dragPosition / nColumns == holdPosition / nColumns) { to_x = x_vlaue; to_y = 0; } else if((holdPosition + 1) % 4 == 0){ to_x = -3 * x_vlaue; to_y = y_vlaue; }else{ to_x = x_vlaue; to_y = 0; } } ViewGroup moveViewGroup = (ViewGroup) getChildAt(holdPosition); Animation moveAnimation = getMoveAnimation(to_x, to_y); moveViewGroup.startAnimation(moveAnimation); //如果是最后一个移动的,那么设置他的最后个动画ID为LastAnimationID if (holdPosition == dropPosition) { LastAnimationID = moveAnimation.toString(); } moveAnimation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { isMoving = true; } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { // 如果为最后个动画结束,那执行下面的方法 if (animation.toString().equalsIgnoreCase(LastAnimationID)) { DragAdapter mDragAdapter = (DragAdapter) getAdapter(); mDragAdapter.exchange(startPosition,dropPosition); startPosition = dropPosition; dragPosition = dropPosition; isMoving = false; } } }); } } } } /** 获取移动的动画 */ public Animation getMoveAnimation(float toXValue, float toYValue) { TranslateAnimation mTranslateAnimation = new TranslateAnimation( Animation.RELATIVE_TO_SELF, 0.0F, Animation.RELATIVE_TO_SELF,toXValue, Animation.RELATIVE_TO_SELF, 0.0F, Animation.RELATIVE_TO_SELF, toYValue);// 当前位置移动到指定位置 mTranslateAnimation.setFillAfter(true);// 设置一个动画效果执行完毕后,View对象保留在终止的位置。 mTranslateAnimation.setDuration(300L); return mTranslateAnimation; } }public class MyGridView extends GridView { public MyGridView(Context paramContext, AttributeSet paramAttributeSet) { super(paramContext, paramAttributeSet); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } }