文章目錄
- 前言
- 效果圖
- 實作原理
- 核心代碼
- 非核心代碼部分
- 專案地址
前言
這篇博客只寫了拖動排序,具體的訂閱功能,有需要的小伙伴也可以看下我之前寫的關于訂閱功能實作的一篇博文👇👇👇(寫的比較早,現在有了更簡便的方法,下次再寫一篇新的)!
Android應用分類訂閱功能(新聞個性化分類訂閱)
效果圖
這里可以看到,長按某個Item以后,進行拖動,可以實作將此Item拖動到該GridView中其他位置的功能

實作原理
通過實作自定義GridView重寫onTouchEvent方法以及實作onItemLongClick介面來實作長按一個item然后用視窗顯示出來,根據手指的移動來移動顯示的視窗,最后通過判斷手指離開螢屏的位置來確定最終item移動到的位置,
核心代碼
DragGridView.java
首先是繼承自GridView,并且實作OnItemLongClickListener介面,再重寫一下onTouchEvent方法;
整體邏輯(理解萬歲):
1、長按某個Item時:在onTouchEvent中獲取當前手指在螢屏上的位置(記錄坐標);在OnItemLongClickListener中通過獲取當前Item的影像資源放入ImageView中,然后通過WindowManager視窗將這個影像方法1.2倍顯示在螢屏上,并且隱藏掉長按的Item;
2、長按以后拖動時:讓Windowmanager視窗隨著手指移動,并且判斷移動的程序中有沒有移動到別的Item上,如果有那就進行排序;
3、停止操作以后:將隱藏掉的Item顯示回來,并且呼叫WindowManager的.removeView()方法移除ImageView影像
這里該寫的注釋基本上都寫了,這里面有幾個Adapter里面寫的方法,Adapter的代碼在這個的下面;
public class DragGridView extends GridView implements AdapterView.OnItemLongClickListener {
private ImageView dragIiewView;//ImageView,影像容器
private WindowManager windowManager;//視窗
private WindowManager.LayoutParams dragParams;//用于記錄視窗展示的位置
private int oldPos;//用于記錄拖動的item的position
private int rawX;//用于記錄初始坐標X
private int rawY;//用于記錄初始坐標Y
private boolean isDrag;//用來判斷當前是否是在拖動的狀態
public DragGridView(Context context) {
super(context);
initView();
}
public DragGridView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public DragGridView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
setOnItemLongClickListener(this);
dragIiewView = new ImageView(getContext());
windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
dragParams = new WindowManager.LayoutParams();
}
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
//記下item的position
oldPos = i;
//獲取長按item的DrawingCache
view.destroyDrawingCache();
view.setDrawingCacheEnabled(true);
//獲取item的Bitmap
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
//設定拖動引數、以及設定顯示出來可以拖動的item放大1.2倍
dragParams.gravity = Gravity.TOP | Gravity.START;
dragParams.width = (int) (1.2f * bitmap.getWidth());
dragParams.height = (int) (1.2f * bitmap.getHeight());
//獲取拖動的中心點
dragParams.x = rawX - dragParams.width / 2;
dragParams.y = rawY - dragParams.height / 2;
dragParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
dragParams.format = PixelFormat.TRANSLUCENT;
dragParams.windowAnimations = 0;
//設定ImageView的影像為本次長按的item的影像
dragIiewView.setImageBitmap(bitmap);
//將ImageView顯示到螢屏上
windowManager.addView(dragIiewView, dragParams);
//設定當前狀態為true
isDrag = true;
//設定長按的item隱藏
((DragGridViewAdapter) getAdapter()).hideView(i);
return true;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
//當手指觸碰螢屏時,記錄下坐標
rawX = (int) ev.getRawX();
rawY = (int) ev.getRawY();
} else if (isDrag && ev.getAction() == MotionEvent.ACTION_MOVE) {
//item被拖動時,記錄拖動程序中的(當前)坐標
dragParams.x = (int) (ev.getRawX() - dragIiewView.getWidth() / 2);
dragParams.y = (int) (ev.getRawY() - dragIiewView.getHeight() / 2);
//更新視窗顯示
windowManager.updateViewLayout(dragIiewView, dragParams);
//獲取拖動程序中,觸摸點所在GridView中item的位置(position)
int newPos = pointToPosition(((int) ev.getX()), (int) ev.getY());
//如果當前位置不等于上次停留的位置,則交換兩次位置的item
if (newPos != AdapterView.INVALID_POSITION && newPos != oldPos) {
((DragGridViewAdapter) getAdapter()).updataView(oldPos, newPos);
oldPos = newPos;
}
} else if (isDrag && ev.getAction() == MotionEvent.ACTION_UP) {
//操作停止時(手指離開螢屏),回歸正常顯示狀態
((DragGridViewAdapter) getAdapter()).showHideView();
//清空視窗
windowManager.removeView(dragIiewView);
//狀態改成false
isDrag = false;
}
return super.onTouchEvent(ev);
}
}
DragGridViewAdapter.java
整個配接器除了加了幾個方法以外,和正常的Adapter沒啥區別,這里主要有三個方法:
1、hideView,這個方法用于隱藏長按的那個Item(如果你的Item比較復雜,這個隱藏的方法可以改寫,這里不具體講怎么改)
2、showHideView,這個方法用于顯示hideView方法隱藏掉的Item(用于拖動操作進行完了以后)
3、updataView,更新GridView的視圖顯示,主要邏輯是:通過判斷移動前Item的position和移動后Item的position,進行比較再進行相應的資料排序(這里排序的實質是進行資料的插入和移除)
public class DragGridViewAdapter extends BaseAdapter {
private List<String> list;
private int hidePos = AdapterView.INVALID_POSITION;
public DragGridViewAdapter(List<String> list) {
this.list = list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int i) {
return list.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
class ViewHolder {
TextView txv;
}
//隱藏item
public void hideView(int pos) {
hidePos = pos;
notifyDataSetChanged();
}
//顯示隱藏了的item
public void showHideView() {
hidePos = AdapterView.INVALID_POSITION;
notifyDataSetChanged();
}
//處理當item的位置發生改變時,更新顯示
public void updataView(int oldPos, int newPos) {
if (oldPos > newPos) {//item從后往前拖動
list.add(newPos, list.get(oldPos));
list.remove(oldPos + 1);
} else if (oldPos < newPos) {//item從前往后拖動
list.add(newPos + 1, list.get(oldPos));
list.remove(oldPos);
}
hidePos = newPos;
notifyDataSetChanged();
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder = new ViewHolder();
if (view == null) {
view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.drag_grid_item, null);
viewHolder.txv = (TextView) view.findViewById(R.id.txv);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
if (i != hidePos) {
viewHolder.txv.setText(list.get(i));
} else {
viewHolder.txv.setText("");
}
return view;
}
}
寫到這里,會寫GridView的小伙伴可以忽略下面的非核心代碼部分,Activity中和正常寫GridView一樣(加資料、實體化配接器、GridView呼叫setAdapter()方法)
非核心代碼部分
DragGridViewActivity.java
這里就簡單的加了20組資料,然后實體化Adapter、呼叫setAdapter()方法
public class DragGridViewActivity extends AppCompatActivity {
private DragGridView gvDrag;
private List<String> list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drag_grid_view);
initView();
list = new ArrayList<>();
for (int i = 0; i < 20; i++) {
list.add("小黑" + i);
}
DragGridViewAdapter adapter = new DragGridViewAdapter(list);
gvDrag.setAdapter(adapter);
}
private void initView() {
gvDrag = (DragGridView) findViewById(R.id.gv_drag);
}
}
activity_drag_grid_view.xml
這里就是一個簡單的自己寫的DragGridView(自定義的那個GridView)
<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"
tools:context=".DragGridViewActivity">
<com.example.asyu.draggridview.DragGridView
android:id="@+id/gv_drag"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="5" />
</LinearLayout>
drag_grid_item.xml
這里也是隨便寫了個Item
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/txv"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_margin="5dp"
android:layout_weight="1"
android:background="#619db4"
android:gravity="center" />
</LinearLayout>
專案地址
專案地址:DragGridView專案地址(GitHub)

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/194896.html
標籤:其他
上一篇:深入Android系統(六)第一個用戶行程-Init行程
下一篇:兩種方法實作登錄回傳上一頁,對上一頁進行判斷,如果不是本網站頁面,就跳轉到個人中心或網站主頁,如果上一頁是本網站頁面就跳轉回到上一頁
