麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁(yè) > 系統(tǒng) > Android > 正文

android ListView和GridView拖拽移位實(shí)現(xiàn)代碼

2020-04-11 12:39:47
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

關(guān)于ListView拖拽移動(dòng)位置,想必大家并不陌生,比較不錯(cuò)的軟件都用到如此功能了.如:搜狐,網(wǎng)易,百度等,但是相比來(lái)說(shuō)還是百度的用戶體驗(yàn)較好,不偏心了,下面看幾個(gè)示例:
/      /      /

首先說(shuō)一下:拖拽ListView的item就不應(yīng)該可以任意移動(dòng),只應(yīng)該在ListView所在的范圍內(nèi),而網(wǎng)易的你看看我都可以移動(dòng)到狀態(tài)欄了,雖然你做了處理,但是用戶體驗(yàn)我個(gè)人感覺(jué)不好,在看看百度的,不僅控制了移動(dòng)范圍,更不錯(cuò)的百度的移動(dòng)起來(lái)會(huì)時(shí)時(shí)的換位,看起來(lái)相當(dāng)?shù)男蜗螅晕艺J(rèn)為這樣相當(dāng)?shù)陌?
說(shuō)明一點(diǎn),我沒(méi)有那么有才,我也是看別人代碼,然后自己整理下.在這里就簡(jiǎn)單記載一下.
首先對(duì)touch事件的處理,從應(yīng)用中,我們可以得出,在我們點(diǎn)擊后面拖拉圖標(biāo)后,就會(huì)創(chuàng)建一個(gè)item的影像視圖.并且可以移動(dòng)該影像,而此時(shí)的ListView不應(yīng)該有touch事件.
onInterceptTouchEvent方法.
[java]

復(fù)制代碼 代碼如下:

/***
* touch事件攔截
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// 按下
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
int x = (int) ev.getX();// 獲取相對(duì)與ListView的x坐標(biāo)
int y = (int) ev.getY();// 獲取相應(yīng)與ListView的y坐標(biāo)
dragSrcPosition = dragPosition = pointToPosition(x, y);
// 無(wú)效不進(jìn)行處理
if (dragPosition == AdapterView.INVALID_POSITION) {
return super.onInterceptTouchEvent(ev);
}

// 獲取當(dāng)前位置的視圖(可見(jiàn)狀態(tài))
ViewGroup itemView = (ViewGroup) getChildAt(dragPosition
- getFirstVisiblePosition());

// 獲取到的dragPoint其實(shí)就是在你點(diǎn)擊指定item項(xiàng)中的高度.
dragPoint = y - itemView.getTop();
// 這個(gè)值是固定的:其實(shí)就是ListView這個(gè)控件與屏幕最頂部的距離(一般為標(biāo)題欄+狀態(tài)欄).
dragOffset = (int) (ev.getRawY() - y);

// 獲取可拖拽的圖標(biāo)
View dragger = itemView.findViewById(R.id.iv_drag_list_item_2);

// x > dragger.getLeft() - 20這句話為了更好的觸摸(-20可以省略)
if (dragger != null && x > dragger.getLeft() - 20) {

upScrollBounce = getHeight() / 3;// 取得向上滾動(dòng)的邊際,大概為該控件的1/3
downScrollBounce = getHeight() * 2 / 3;// 取得向下滾動(dòng)的邊際,大概為該控件的2/3

itemView.setDrawingCacheEnabled(true);// 開(kāi)啟cache.
Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache());// 根據(jù)cache創(chuàng)建一個(gè)新的bitmap對(duì)象.
startDrag(bm, y);// 初始化影像
}
// return false;
}

return super.onInterceptTouchEvent(ev);
}

這個(gè)方法的作用很簡(jiǎn)單:當(dāng)我們摁下的如果是可拖拽的圖標(biāo),那么進(jìn)行初始化該Item的映像試圖.
而在這里如果大家對(duì)WindowManager和WindowManager.LayoutParams不熟悉的朋友先去參考下這篇文章,要對(duì)WindowManager有一定的了解,簡(jiǎn)單的會(huì)應(yīng)用.
接下來(lái)我們看onTouchEvent事件:
[java]
復(fù)制代碼 代碼如下:

/**
* 觸摸事件處理
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
// item的view不為空,且獲取的dragPosition有效
if (dragImageView != null && dragPosition != INVALID_POSITION) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_UP:
int upY = (int) ev.getY();
stopDrag();
onDrop(upY);
break;
case MotionEvent.ACTION_MOVE:
int moveY = (int) ev.getY();
onDrag(moveY);

break;
case MotionEvent.ACTION_DOWN:
break;
default:
break;
}
return true;// 取消ListView滑動(dòng).
}

return super.onTouchEvent(ev);
}

簡(jiǎn)單說(shuō)明:首先在Touch中,我們要進(jìn)行判斷,是否點(diǎn)擊的是拖動(dòng)圖標(biāo),如果是的話,那么對(duì)ACTION_MOVE and ACTION_UP相應(yīng)事件進(jìn)行處理,并且返回true or false.作用:取消ListView自身的Touch事件.如果不是的話,執(zhí)行ListView 本身的Touch事件.
大致就介紹這么多,具體的實(shí)現(xiàn),還是大家看源碼吧,我注釋的還算清晰,只要大家仔細(xì)看的話,一定可以掌握的,為什么這么說(shuō)呢,技術(shù)只有在掌握了情況下才可以進(jìn)行拓展.
對(duì)了,提醒大家要理解這三句話:
getRawX()和getRawY():獲得的是相對(duì)屏幕的位置.
getX()和getY():獲得的永遠(yuǎn)是相對(duì)view的觸摸位置 坐標(biāo)(這兩個(gè)值不會(huì)超過(guò)view的長(zhǎng)度和寬度)。
getLeft , getTop, getBottom,getRight, 這個(gè)指的是該控件相對(duì)于父控件的距離.
源碼:
[java] 
復(fù)制代碼 代碼如下:

package com.jj.drag;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;

import com.jj.drag.MainActivity.DragListAdapter;

/***
* 自定義拖拽ListView
*
* @author zhangjia
*
*/
public class DragListView extends ListView {

private WindowManager windowManager;// windows窗口控制類
private WindowManager.LayoutParams windowParams;// 用于控制拖拽項(xiàng)的顯示的參數(shù)

private int scaledTouchSlop;// 判斷滑動(dòng)的一個(gè)距離,scroll的時(shí)候會(huì)用到(24)

private ImageView dragImageView;// 被拖拽的項(xiàng)(item),其實(shí)就是一個(gè)ImageView
private int dragSrcPosition;// 手指拖動(dòng)項(xiàng)原始在列表中的位置
private int dragPosition;// 手指點(diǎn)擊準(zhǔn)備拖動(dòng)的時(shí)候,當(dāng)前拖動(dòng)項(xiàng)在列表中的位置.

private int dragPoint;// 在當(dāng)前數(shù)據(jù)項(xiàng)中的位置
private int dragOffset;// 當(dāng)前視圖和屏幕的距離(這里只使用了y方向上)

private int upScrollBounce;// 拖動(dòng)的時(shí)候,開(kāi)始向上滾動(dòng)的邊界
private int downScrollBounce;// 拖動(dòng)的時(shí)候,開(kāi)始向下滾動(dòng)的邊界

private final static int step = 1;// ListView 滑動(dòng)步伐.

private int current_Step;// 當(dāng)前步伐.

/***
* 構(gòu)造方法
*
* @param context
* @param attrs
*/
public DragListView(Context context, AttributeSet attrs) {
super(context, attrs);
}

/***
* touch事件攔截
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// 按下
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
int x = (int) ev.getX();// 獲取相對(duì)與ListView的x坐標(biāo)
int y = (int) ev.getY();// 獲取相應(yīng)與ListView的y坐標(biāo)
dragSrcPosition = dragPosition = pointToPosition(x, y);
// 無(wú)效不進(jìn)行處理
if (dragPosition == AdapterView.INVALID_POSITION) {
return super.onInterceptTouchEvent(ev);
}

// 獲取當(dāng)前位置的視圖(可見(jiàn)狀態(tài))
ViewGroup itemView = (ViewGroup) getChildAt(dragPosition
- getFirstVisiblePosition());

// 獲取到的dragPoint其實(shí)就是在你點(diǎn)擊指定item項(xiàng)中的高度.
dragPoint = y - itemView.getTop();
// 這個(gè)值是固定的:其實(shí)就是ListView這個(gè)控件與屏幕最頂部的距離(一般為標(biāo)題欄+狀態(tài)欄).
dragOffset = (int) (ev.getRawY() - y);

// 獲取可拖拽的圖標(biāo)
View dragger = itemView.findViewById(R.id.iv_drag_list_item_2);

// x > dragger.getLeft() - 20這句話為了更好的觸摸(-20可以省略)
if (dragger != null && x > dragger.getLeft() - 20) {

upScrollBounce = getHeight() / 3;// 取得向上滾動(dòng)的邊際,大概為該控件的1/3
downScrollBounce = getHeight() * 2 / 3;// 取得向下滾動(dòng)的邊際,大概為該控件的2/3

itemView.setDrawingCacheEnabled(true);// 開(kāi)啟cache.
Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache());// 根據(jù)cache創(chuàng)建一個(gè)新的bitmap對(duì)象.
startDrag(bm, y);// 初始化影像
}
}

return super.onInterceptTouchEvent(ev);
}

/**
* 觸摸事件處理
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
// item的view不為空,且獲取的dragPosition有效
if (dragImageView != null && dragPosition != INVALID_POSITION) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_UP:
int upY = (int) ev.getY();
stopDrag();
onDrop(upY);
break;
case MotionEvent.ACTION_MOVE:
int moveY = (int) ev.getY();
onDrag(moveY);
break;
case MotionEvent.ACTION_DOWN:
break;
default:
break;
}
return true;// 取消ListView滑動(dòng).
}

return super.onTouchEvent(ev);
}

/**
* 準(zhǔn)備拖動(dòng),初始化拖動(dòng)項(xiàng)的圖像
*
* @param bm
* @param y
*/
private void startDrag(Bitmap bm, int y) {
// stopDrag();
/***
* 初始化window.
*/
windowParams = new WindowManager.LayoutParams();
windowParams.gravity = Gravity.TOP;
windowParams.x = 0;
windowParams.y = y - dragPoint + dragOffset;
windowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;

windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE// 不需獲取焦點(diǎn)
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE// 不需接受觸摸事件
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON// 保持設(shè)備常開(kāi),并保持亮度不變。
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;// 窗口占滿整個(gè)屏幕,忽略周圍的裝飾邊框(例如狀態(tài)欄)。此窗口需考慮到裝飾邊框的內(nèi)容。

// windowParams.format = PixelFormat.TRANSLUCENT;// 默認(rèn)為不透明,這里設(shè)成透明效果.
windowParams.windowAnimations = 0;// 窗口所使用的動(dòng)畫設(shè)置

ImageView imageView = new ImageView(getContext());
imageView.setImageBitmap(bm);
windowManager = (WindowManager) getContext().getSystemService("window");
windowManager.addView(imageView, windowParams);
dragImageView = imageView;

}

/**
* 拖動(dòng)執(zhí)行,在Move方法中執(zhí)行
*
* @param y
*/
public void onDrag(int y) {
int drag_top = y - dragPoint;// 拖拽view的top值不能<0,否則則出界.
if (dragImageView != null && drag_top >= 0) {
windowParams.alpha = 0.5f;// 透明度
windowParams.y = y - dragPoint + dragOffset;// 移動(dòng)y值.//記得要加上dragOffset,windowManager計(jì)算的是整個(gè)屏幕.(標(biāo)題欄和狀態(tài)欄都要算上)
windowManager.updateViewLayout(dragImageView, windowParams);// 時(shí)時(shí)移動(dòng).
}
// 為了避免滑動(dòng)到分割線的時(shí)候,返回-1的問(wèn)題
int tempPosition = pointToPosition(0, y);
if (tempPosition != INVALID_POSITION) {
dragPosition = tempPosition;

}
doScroller(y);
}

/***
* ListView的移動(dòng).
* 要明白移動(dòng)原理:當(dāng)映像移動(dòng)到下端的時(shí)候,ListView向上滑動(dòng),當(dāng)映像移動(dòng)到上端的時(shí)候,ListView要向下滑動(dòng)。正好和實(shí)際的相反.
*
*/

public void doScroller(int y) {
Log.e("jj", "y=" + y);
Log.e("jj", "upScrollBounce=" + upScrollBounce);
// ListView需要下滑
if (y < upScrollBounce) {
current_Step = step + (upScrollBounce - y) / 10;// 時(shí)時(shí)步伐
}// ListView需要上滑
else if (y > downScrollBounce) {
current_Step = -(step + (y - downScrollBounce)) / 10;// 時(shí)時(shí)步伐
} else {
current_Step = 0;
}

// 獲取你拖拽滑動(dòng)到位置及顯示item相應(yīng)的view上(注:可顯示部分)(position)
View view = getChildAt(dragPosition - getFirstVisiblePosition());
// 真正滾動(dòng)的方法setSelectionFromTop()
setSelectionFromTop(dragPosition, view.getTop() + current_Step);

}

/**
* 停止拖動(dòng),刪除影像
*/
public void stopDrag() {
if (dragImageView != null) {
windowManager.removeView(dragImageView);
dragImageView = null;
}
}

/**
* 拖動(dòng)放下的時(shí)候
*
* @param y
*/
public void onDrop(int y) {

// 為了避免滑動(dòng)到分割線的時(shí)候,返回-1的問(wèn)題
int tempPosition = pointToPosition(0, y);
if (tempPosition != INVALID_POSITION) {
dragPosition = tempPosition;
}

// 超出邊界處理(如果向上超過(guò)第二項(xiàng)Top的話,那么就放置在第一個(gè)位置)
if (y < getChildAt(0).getTop()) {
// 超出上邊界
dragPosition = 0;
// 如果拖動(dòng)超過(guò)最后一項(xiàng)的最下邊那么就防止在最下邊
} else if (y > getChildAt(getChildCount() - 1).getBottom()) {
// 超出下邊界
dragPosition = getAdapter().getCount() - 1;
}

// 數(shù)據(jù)交換
if (dragPosition < getAdapter().getCount()) {
DragListAdapter adapter = (DragListAdapter) getAdapter();
adapter.update(dragSrcPosition, dragPosition);
}

}

}

下面我說(shuō)下適配器:
[java] 
復(fù)制代碼 代碼如下:

/***
* 自定義適配器
*
* @author zhangjia
*
*/
class DragListAdapter extends BaseAdapter {
private ArrayList<String> arrayTitles;
private ArrayList<Integer> arrayDrawables;
private Context context;

public DragListAdapter(Context context, ArrayList<String> arrayTitles,
ArrayList<Integer> arrayDrawables) {
this.context = context;
this.arrayTitles = arrayTitles;
this.arrayDrawables = arrayDrawables;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
/***
* 在這里盡可能每次都進(jìn)行實(shí)例化新的,這樣在拖拽ListView的時(shí)候不會(huì)出現(xiàn)錯(cuò)亂.
* 具體原因不明,不過(guò)這樣經(jīng)過(guò)測(cè)試,目前沒(méi)有發(fā)現(xiàn)錯(cuò)亂。雖說(shuō)效率不高,但是做拖拽LisView足夠了。
*/
view = LayoutInflater.from(context).inflate(
R.layout.drag_list_item, null);

TextView textView = (TextView) view
.findViewById(R.id.tv_drag_list_item_text);
ImageView imageView = (ImageView) view
.findViewById(R.id.iv_drag_list_item_1);
imageView.setImageResource(arrayDrawables.get(position));
textView.setText(arrayTitles.get(position));
return view;
}

/***
* 動(dòng)態(tài)修改ListVIiw的方位.
*
* @param start
* 點(diǎn)擊移動(dòng)的position
* @param down
* 松開(kāi)時(shí)候的position
*/
public void update(int start, int down) {
// 獲取刪除的東東.
String title = arrayTitles.get(start);
int drawable_id = arrayDrawables.get(start);

arrayTitles.remove(start);// 刪除該項(xiàng)
arrayDrawables.remove(start);// 刪除該項(xiàng)

arrayTitles.add(down, title);// 添加刪除項(xiàng)
arrayDrawables.add(down, drawable_id);// 添加刪除項(xiàng)

notifyDataSetChanged();// 刷新ListView
}

@Override
public int getCount() {

return Title.length;
}

@Override
public Object getItem(int position) {
return Title[position];
}

@Override
public long getItemId(int position) {
return position;
}

}


這里不過(guò)多解釋了,相信大家都看的明白.如果疑問(wèn)請(qǐng)留言.
展示下運(yùn)行效果:

效果看起來(lái)還行吧,如果覺(jué)得不錯(cuò)的話,記得要贊一個(gè)哦.

下面我們接著修改,模擬百度嘛,誰(shuí)讓百度這么牛叉呢.
思路:點(diǎn)中拖拉圖標(biāo)的時(shí)候,每次移動(dòng)只要dragPosition發(fā)生改變,也就是我移動(dòng)到了下一個(gè)位置,那么此時(shí)我就進(jìn)行交換執(zhí)行update.并且除了第一次移動(dòng)外,在每次交換后要除去映射源的顯示,這樣用戶覺(jué)得這里的空位就是就是為我準(zhǔn)備的,比較人性化.
實(shí)現(xiàn)起來(lái)并不復(fù)雜,前提是你得掌握上面的操作.
源碼如下;
[java]

復(fù)制代碼 代碼如下:

package com.jj.drag;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;

import com.jj.drag.MainActivity.DragListAdapter;

public class DragListView extends ListView {

private WindowManager windowManager;// windows窗口控制類
private WindowManager.LayoutParams windowParams;// 用于控制拖拽項(xiàng)的顯示的參數(shù)

private int scaledTouchSlop;// 判斷滑動(dòng)的一個(gè)距離,scroll的時(shí)候會(huì)用到(24)

private ImageView dragImageView;// 被拖拽的項(xiàng)(item),其實(shí)就是一個(gè)ImageView
private int dragSrcPosition;// 手指拖動(dòng)項(xiàng)原始在列表中的位置
private int dragPosition;// 手指點(diǎn)擊準(zhǔn)備拖動(dòng)的時(shí)候,當(dāng)前拖動(dòng)項(xiàng)在列表中的位置.

private int dragPoint;// 在當(dāng)前數(shù)據(jù)項(xiàng)中的位置
private int dragOffset;// 當(dāng)前視圖和屏幕的距離(這里只使用了y方向上)

private int upScrollBounce;// 拖動(dòng)的時(shí)候,開(kāi)始向上滾動(dòng)的邊界
private int downScrollBounce;// 拖動(dòng)的時(shí)候,開(kāi)始向下滾動(dòng)的邊界

private final static int step = 1;// ListView 滑動(dòng)步伐.

private int current_Step;// 當(dāng)前步伐.

private int temChangId;// 臨時(shí)交換id

private boolean isLock;// 是否上鎖.

public void setLock(boolean isLock) {
this.isLock = isLock;
}

public DragListView(Context context, AttributeSet attrs) {
super(context, attrs);
scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}

/***
* touch事件攔截 在這里我進(jìn)行相應(yīng)攔截,
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// 按下
if (ev.getAction() == MotionEvent.ACTION_DOWN && !isLock) {
int x = (int) ev.getX();// 獲取相對(duì)與ListView的x坐標(biāo)
int y = (int) ev.getY();// 獲取相應(yīng)與ListView的y坐標(biāo)
temChangId = dragSrcPosition = dragPosition = pointToPosition(x, y);
// 無(wú)效不進(jìn)行處理
if (dragPosition == AdapterView.INVALID_POSITION) {
return super.onInterceptTouchEvent(ev);
}

// 獲取當(dāng)前位置的視圖(可見(jiàn)狀態(tài))
ViewGroup itemView = (ViewGroup) getChildAt(dragPosition
- getFirstVisiblePosition());

// 獲取到的dragPoint其實(shí)就是在你點(diǎn)擊指定item項(xiàng)中的高度.
dragPoint = y - itemView.getTop();
// 這個(gè)值是固定的:其實(shí)就是ListView這個(gè)控件與屏幕最頂部的距離(一般為標(biāo)題欄+狀態(tài)欄).
dragOffset = (int) (ev.getRawY() - y);

// 獲取可拖拽的圖標(biāo)
View dragger = itemView.findViewById(R.id.iv_drag_list_item_2);

// x > dragger.getLeft() - 20這句話為了更好的觸摸(-20可以省略)
if (dragger != null && x > dragger.getLeft() - 20) {

upScrollBounce = getHeight() / 3;// 取得向上滾動(dòng)的邊際,大概為該控件的1/3
downScrollBounce = getHeight() * 2 / 3;// 取得向下滾動(dòng)的邊際,大概為該控件的2/3
itemView.setBackgroundColor(Color.BLUE);
itemView.setDrawingCacheEnabled(true);// 開(kāi)啟cache.
Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache());// 根據(jù)cache創(chuàng)建一個(gè)新的bitmap對(duì)象.
startDrag(bm, y);// 初始化影像
}
return false;
}

return super.onInterceptTouchEvent(ev);
}

/**
* 觸摸事件處理
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
// item的view不為空,且獲取的dragPosition有效
if (dragImageView != null && dragPosition != INVALID_POSITION
&& !isLock) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_UP:
int upY = (int) ev.getY();
stopDrag();
onDrop(upY);
break;
case MotionEvent.ACTION_MOVE:
int moveY = (int) ev.getY();
onDrag(moveY);

break;
case MotionEvent.ACTION_DOWN:
break;
default:
break;
}
return true;// 取消ListView滑動(dòng).
}

return super.onTouchEvent(ev);
}

/**
* 準(zhǔn)備拖動(dòng),初始化拖動(dòng)項(xiàng)的圖像
*
* @param bm
* @param y
*/
private void startDrag(Bitmap bm, int y) {
// stopDrag();
/***
* 初始化window.
*/
windowParams = new WindowManager.LayoutParams();
windowParams.gravity = Gravity.TOP;
windowParams.x = 0;
windowParams.y = y - dragPoint + dragOffset;
windowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;

windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE// 不需獲取焦點(diǎn)
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE// 不需接受觸摸事件
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON// 保持設(shè)備常開(kāi),并保持亮度不變。
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;// 窗口占滿整個(gè)屏幕,忽略周圍的裝飾邊框(例如狀態(tài)欄)。此窗口需考慮到裝飾邊框的內(nèi)容。

// windowParams.format = PixelFormat.TRANSLUCENT;// 默認(rèn)為不透明,這里設(shè)成透明效果.
windowParams.windowAnimations = 0;// 窗口所使用的動(dòng)畫設(shè)置

ImageView imageView = new ImageView(getContext());
imageView.setImageBitmap(bm);
windowManager = (WindowManager) getContext().getSystemService("window");
windowManager.addView(imageView, windowParams);
dragImageView = imageView;

}

/**
* 拖動(dòng)執(zhí)行,在Move方法中執(zhí)行
*
* @param y
*/
public void onDrag(int y) {
int drag_top = y - dragPoint;// 拖拽view的top值不能<0,否則則出界.
if (dragImageView != null && drag_top >= 0) {
windowParams.alpha = 0.5f;
windowParams.y = y - dragPoint + dragOffset;
windowManager.updateViewLayout(dragImageView, windowParams);// 時(shí)時(shí)移動(dòng).
}
// 為了避免滑動(dòng)到分割線的時(shí)候,返回-1的問(wèn)題
int tempPosition = pointToPosition(0, y);
if (tempPosition != INVALID_POSITION) {
dragPosition = tempPosition;
}

onChange(y);// 時(shí)時(shí)交換

doScroller(y);// listview移動(dòng).
}

/***
* ListView的移動(dòng).
* 要明白移動(dòng)原理:當(dāng)我移動(dòng)到下端的時(shí)候,ListView向上滑動(dòng),當(dāng)我移動(dòng)到上端的時(shí)候,ListView要向下滑動(dòng)。正好和實(shí)際的相反.
*
*/

public void doScroller(int y) {
// Log.e("jj", "y=" + y);
// Log.e("jj", "upScrollBounce=" + upScrollBounce);
// ListView需要下滑
if (y < upScrollBounce) {
current_Step = step + (upScrollBounce - y) / 10;// 時(shí)時(shí)步伐
}// ListView需要上滑
else if (y > downScrollBounce) {
current_Step = -(step + (y - downScrollBounce)) / 10;// 時(shí)時(shí)步伐
} else {
current_Step = 0;
}

// 獲取你拖拽滑動(dòng)到位置及顯示item相應(yīng)的view上(注:可顯示部分)(position)
View view = getChildAt(dragPosition - getFirstVisiblePosition());
// 真正滾動(dòng)的方法setSelectionFromTop()
setSelectionFromTop(dragPosition, view.getTop() + current_Step);

}

/**
* 停止拖動(dòng),刪除影像
*/
public void stopDrag() {
if (dragImageView != null) {
windowManager.removeView(dragImageView);
dragImageView = null;
}
}

/***
* 拖動(dòng)時(shí)時(shí)change
*/
private void onChange(int y) {
// 數(shù)據(jù)交換
if (dragPosition < getAdapter().getCount()) {
DragListAdapter adapter = (DragListAdapter) getAdapter();
adapter.isHidden = false;
if (dragPosition != temChangId) {
adapter.update(temChangId, dragPosition);
temChangId = dragPosition;// 將點(diǎn)擊最初所在位置position付給臨時(shí)的,用于判斷是否換位.
}
}

// 為了避免滑動(dòng)到分割線的時(shí)候,返回-1的問(wèn)題
int tempPosition = pointToPosition(0, y);
if (tempPosition != INVALID_POSITION) {
dragPosition = tempPosition;
}

// 超出邊界處理(如果向上超過(guò)第二項(xiàng)Top的話,那么就放置在第一個(gè)位置)
if (y < getChildAt(0).getTop()) {
// 超出上邊界
dragPosition = 0;
// 如果拖動(dòng)超過(guò)最后一項(xiàng)的最下邊那么就防止在最下邊
} else if (y > getChildAt(getChildCount() - 1).getBottom()) {
// 超出下邊界
dragPosition = getAdapter().getCount() - 1;
}

}

/**
* 拖動(dòng)放下的時(shí)候
*
* @param y
*/
public void onDrop(int y) {
// 數(shù)據(jù)交換
if (dragPosition < getAdapter().getCount()) {
DragListAdapter adapter = (DragListAdapter) getAdapter();
adapter.isHidden = false;
adapter.notifyDataSetChanged();// 刷新.
}
}

}

因?yàn)槲覀円獣r(shí)時(shí)交換位置,所以將原先的拖動(dòng)方法onDrop方法移動(dòng)到onChange中.具體的還是看源碼吧.
另外的就是對(duì)適配器的修改,因?yàn)槟阋獙?duì)特殊的item進(jìn)行隱藏之類的操作,這些代碼我就不寫了,我會(huì)將案例上傳網(wǎng)上,不懂的可以下載源碼.
好了還是我們來(lái)觀看下效果吧.

怎么樣,這個(gè)效果看起來(lái)要比上面那個(gè)效果更人性化點(diǎn)吧,我的操作或許有點(diǎn)快,不信的話,你自己手機(jī)體驗(yàn)一下吧.
關(guān)于ListView拖拽就說(shuō)到這里,如有不足請(qǐng)大家自己創(chuàng)新.

下面我們接著對(duì)GridView的拖拽簡(jiǎn)單說(shuō)明.因?yàn)檫@些在項(xiàng)目中我們都會(huì)用到,所以既然做到就做全面點(diǎn)吧.好了大家接著往下看吧.
首先說(shuō)明,原理一樣,都是拖動(dòng)映像,記錄拖動(dòng)位置,然后調(diào)用notifyDataSetChanged更新UI.
而GridView不同的是你要根據(jù)x,y值共同獲取點(diǎn)擊的position和移動(dòng)至的position,而ListView因?yàn)椴簧婕皒坐標(biāo).
嗯,最初的原始移動(dòng)我就不給大家展示了,效果也不是很友好,我直接展示時(shí)時(shí)更新的那種方法.效果類是與上面那個(gè)時(shí)時(shí)更新ListView一樣。
原理也一樣.下面我們直接看代碼吧.
[java]

復(fù)制代碼 代碼如下:

package com.jj.draggrid;

import java.util.logging.Handler;

import com.jj.draggrid.MainActivity.DragGridAdapter;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.Toast;

/***
* 自定義拖拽GridView
*
* @author zhangjia
*
*/

public class DragGridView extends GridView {

private WindowManager windowManager;// windows窗口控制類
private WindowManager.LayoutParams windowParams;// 用于控制拖拽項(xiàng)的顯示的參數(shù)

private int scaledTouchSlop;// 判斷滑動(dòng)的一個(gè)距離,scroll的時(shí)候會(huì)用到(24)

private ImageView dragImageView;// 被拖拽的項(xiàng)(item),其實(shí)就是一個(gè)ImageView
private int dragSrcPosition;// 手指拖動(dòng)項(xiàng)原始在列表中的位置
private int dragPosition;// 手指點(diǎn)擊準(zhǔn)備拖動(dòng)的時(shí)候,當(dāng)前拖動(dòng)項(xiàng)在列表中的位置.

private int dragPointX;// 在當(dāng)前數(shù)據(jù)項(xiàng)中的位置
private int dragPointY;// 在當(dāng)前數(shù)據(jù)項(xiàng)中的位置
private int dragOffsetX;// 當(dāng)前視圖和屏幕的距離(這里只使用了x方向上)
private int dragOffsetY;// 當(dāng)前視圖和屏幕的距離(這里只使用了y方向上)

private int upScrollBounce;// 拖動(dòng)的時(shí)候,開(kāi)始向上滾動(dòng)的邊界
private int downScrollBounce;// 拖動(dòng)的時(shí)候,開(kāi)始向下滾動(dòng)的邊界

private int temChangId;// 臨時(shí)交換id

private boolean isDoTouch = false;// touch是否可用

private boolean isHide = false;// 是否隱藏

private Handler handler;

public void setDoTouch(boolean isDoTouch) {
this.isDoTouch = isDoTouch;
}

public DragGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {

if (ev.getAction() == MotionEvent.ACTION_DOWN) {
int x = (int) ev.getX();
int y = (int) ev.getY();

temChangId = dragSrcPosition = dragPosition = pointToPosition(x, y);

if (dragPosition == AdapterView.INVALID_POSITION) {
return super.onInterceptTouchEvent(ev);
}

ViewGroup itemView = (ViewGroup) getChildAt(dragPosition
- getFirstVisiblePosition());

dragPointX = x - itemView.getLeft();
dragPointY = y - itemView.getTop();
dragOffsetX = (int) (ev.getRawX() - x);
dragOffsetY = (int) (ev.getRawY() - y);

View dragger = itemView.findViewById(R.id.drag_grid_item);

/***
* 判斷是否選中拖動(dòng)圖標(biāo)
*/
if (dragger != null && dragPointX > dragger.getLeft()
&& dragPointX < dragger.getRight()
&& dragPointY > dragger.getTop()
&& dragPointY < dragger.getBottom() + 20) {

upScrollBounce = getHeight() / 4;
downScrollBounce = getHeight() * 3 / 4;

itemView.setDrawingCacheEnabled(true);
Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache());
startDrag(bm, x, y);// 初始話映像

dragger.setVisibility(View.INVISIBLE);// 隱藏該項(xiàng).
}
}

return super.onInterceptTouchEvent(ev);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {

if (dragImageView != null && dragPosition != INVALID_POSITION
&& isDoTouch) {
int action = ev.getAction();
switch (action) {
/***
*
*/
case MotionEvent.ACTION_UP:
int upX = (int) ev.getX();
int upY = (int) ev.getY();
stopDrag();// 刪除映像
onDrop(upX, upY);// 松開(kāi)
// isDoTouch = false;
break;
/***
* 拖拽item
*
*/
case MotionEvent.ACTION_MOVE:
int moveX = (int) ev.getX();
int moveY = (int) ev.getY();
onDrag(moveX, moveY);// 拖拽
break;
case MotionEvent.ACTION_DOWN:
int downX = (int) ev.getX();
int downY = (int) ev.getY();
onHide(downX, downY);// 隱藏該項(xiàng)
break;
default:
break;
}
return true;
}

return super.onTouchEvent(ev);
}

/**
* 準(zhǔn)備拖動(dòng),初始化拖動(dòng)項(xiàng)的圖像
*
* @param bm
* @param y
*/
public void startDrag(Bitmap bm, int x, int y) {

windowParams = new WindowManager.LayoutParams();
windowParams.gravity = Gravity.TOP | Gravity.LEFT;
windowParams.x = x - dragPointX + dragOffsetX;
windowParams.y = y - dragPointY + dragOffsetY;
windowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;

windowParams.windowAnimations = 0;

ImageView imageView = new ImageView(getContext());
imageView.setImageBitmap(bm);
windowManager = (WindowManager) getContext().getSystemService("window");
windowManager.addView(imageView, windowParams);
dragImageView = imageView;

}

/***
* 拖動(dòng)時(shí)時(shí)change
*/
private void onChange(int x, int y) {
// 獲取適配器
DragGridAdapter adapter = (DragGridAdapter) getAdapter();
// 數(shù)據(jù)交換
if (dragPosition < getAdapter().getCount()) {
// 不相等的情況下要進(jìn)行換位,相等的情況下說(shuō)明正在移動(dòng)
if (dragPosition != temChangId) {
adapter.update(temChangId, dragPosition);// 進(jìn)行換位
temChangId = dragPosition;// 將點(diǎn)擊最初所在位置position付給臨時(shí)的,用于判斷是否換位.
}

}

// 為了避免滑動(dòng)到分割線的時(shí)候,返回-1的問(wèn)題
int tempPosition = pointToPosition(x, y);
if (tempPosition != INVALID_POSITION) {
dragPosition = tempPosition;
}

}

/***
* 拖動(dòng)執(zhí)行,在Move方法中執(zhí)行
*
* @param x
* @param y
*/
public void onDrag(int x, int y) {
// 移動(dòng)
if (dragImageView != null) {
windowParams.alpha = 0.8f;
windowParams.x = x - dragPointX + dragOffsetX;
windowParams.y = y - dragPointY + dragOffsetY;
windowManager.updateViewLayout(dragImageView, windowParams);
}

onChange(x, y);// 時(shí)時(shí)交換

// 滾動(dòng)
if (y < upScrollBounce || y > downScrollBounce) {
// 使用setSelection來(lái)實(shí)現(xiàn)滾動(dòng)
setSelection(dragPosition);
}

}

/***
* 隱藏該選項(xiàng)
*/
private void onHide(int x, int y) {
// 獲取適配器
DragGridAdapter adapter = (DragGridAdapter) getAdapter();
// 為了避免滑動(dòng)到分割線的時(shí)候,返回-1的問(wèn)題
int tempPosition = pointToPosition(x, y);
if (tempPosition != INVALID_POSITION) {
dragPosition = tempPosition;
}
adapter.setIsHidePosition(dragPosition);

}

/**
* 停止拖動(dòng),刪除影像
*/
public void stopDrag() {
if (dragImageView != null) {
windowManager.removeView(dragImageView);
dragImageView = null;
}
}

/***
* 拖動(dòng)放下的時(shí)候
*
* @param x
* @param y
*/
public void onDrop(int x, int y) {

DragGridAdapter adapter = (DragGridAdapter) getAdapter();
adapter.setIsHidePosition(-1);// 不進(jìn)行隱藏

}

}

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 人成免费网站 | fc2成人免费人成在线观看播放 | 黄色va视频 | 黄色毛片视频在线观看 | 欧美精品网址 | 91成人免费电影 | 久久草草影视免费网 | 精品成人免费视频 | 激情小说图 | 日产精品一区二区三区在线观看 | 国产又粗又爽又深的免费视频 | 精品国产99久久久久久宅男i | 在线观看精品视频 | 久久99国产精品久久99 | av电影网在线观看 | 黄色免费高清网站 | 久久久久亚洲精品国产 | 日韩欧美精品电影 | 久久网综合 | 刘亦菲一区二区三区免费看 | 叉逼视频| 一色屋任你操 | 日本精品中文字幕 | 国产一区二区三区四区五区在线 | 羞羞视频免费网站男男 | 91情侣在线偷精品国产 | 日本中文字幕高清 | 久久久久久久国产a∨ | 国产成人自拍小视频 | 深夜福利视频免费观看 | 黄网站免费观看视频 | 午夜天堂在线 | 国产精品午夜未成人免费观看 | 久久国产精品二国产精品 | 久久人人爽人人爽人人片av高清 | 国产流白浆高潮在线观看 | 欧美成人精品一区二区 | 久久亚洲精选 | 欧美精品一区二区三区在线 | 日本视频在线免费观看 | 国产亚洲精品视频中文字幕 |