Android 仿網(wǎng)易新聞客戶端分類排序功能
先來看看網(wǎng)易新聞客戶端以及自己實現(xiàn)的效果圖,效果當然還是網(wǎng)易的好

gridviewsort.gif

如何實現(xiàn)拖拽一個Item
用WindowManager添加一個ImageView,并且將這個ImageView的顯示圖片設置成被拖拽item的截圖,截圖可以通過View的getDrawingCache獲得。拖拽的時候,隱藏原始的item。處理觸摸事件的ActionMove,調(diào)整ImageView的位置,跟隨手指移動。在ActionUp的時候removeView
GridView
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l)
{
// 至少有兩個item的時候,才有排序
if (getChildCount() >= 2)
{
mView = view;
// 在調(diào)用getDrawingCache必須先調(diào)用
view.setDrawingCacheEnabled(true);
// 獲取截圖并設置
Bitmap bitmap = view.getDrawingCache();
mDragItemView.setImageBitmap(bitmap);
// 設置拖拽的imageview的params
mDragItemLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
mDragItemLayoutParams.width = bitmap.getWidth();
mDragItemLayoutParams.height = bitmap.getHeight();
mDragItemLayoutParams.x = (mDownX - mDragItemLayoutParams.width / 2);
mDragItemLayoutParams.y = (mDownY - mDragItemLayoutParams.height / 2);
// 設置拖拽imageview的中心位于長按點擊點
mDragItemLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE //不接受按鍵事件
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE // 不接收觸摸事件
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON // 保持常亮
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; // place the window within the entire screen, ignoring decorations around the border (such as the status bar)
mDragItemLayoutParams.format = PixelFormat.TRANSLUCENT;
mDragItemLayoutParams.windowAnimations = 0;
// 往WindowManager中添加拖拽的View
mWindowManager.addView(mDragItemView, mDragItemLayoutParams);
((GridViewSortAdapter) getAdapter()).init();
((GridViewSortAdapter) getAdapter()).hideView(i);
Log.d(TAG, "long click = " + i);
mDragStarted = true;
}
return true;
}
@Override
public boolean onTouchEvent(MotionEvent ev)
{
switch (ev.getAction() & ev.getActionMasked())
{
case MotionEvent.ACTION_DOWN:
mDownX = (int) ev.getRawX();
mDownY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
if (mDragStarted)
{
// 保持中心
mDragItemLayoutParams.x = (int) (ev.getRawX() - mDragItemView.getWidth() / 2);
mDragItemLayoutParams.y = (int) (ev.getRawY() - mDragItemView.getHeight() / 2);
// 更新params
mWindowManager.updateViewLayout(mDragItemView, mDragItemLayoutParams);
// ......
}
break;
case MotionEvent.ACTION_UP:
// ......
break;
}
return super.onTouchEvent(ev);
}
如何實現(xiàn)隱藏拖拽的Item
在開始拖拽的時候,把隱藏的item的position告訴Adapter,調(diào)用Adapter的notifyDataSetChanged刷新數(shù)據(jù),在getView方法中判斷當前的構建的item的position是不是需要隱藏的position是的話就設置view為inVisible
GridView
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l)
{
// ......
((GridViewSortAdapter) getAdapter()).hideView(i);
// ......
}
GridViewSortAdapter
public void hideView(int item)
{
// ......
mStartHideItemPosition = item;
notifyDataSetChanged();
}
private int mStartHideItemPosition = AdapterView.INVALID_POSITION;
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder = null;
if (convertView == null)
{
convertView = LayoutInflater.from(mContext).inflate(R.layout.view_item_grid_view_sort, null);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.view_item_grid_view_sort_title);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
holder.title.setText(mTypeTitle.get(position));
if (mStartHideItemPosition == position)
{
convertView.setVisibility(View.INVISIBLE);
}
else
{
convertView.setVisibility(View.VISIBLE);
}
return convertView;
}
如何知道當前拖拽到哪一個item之上
要想在拖拽到其他item上面時互換位置,那必須得知道當前拖拽到了哪一個item之上。GrideView提供了一個方法叫pointToPosition,可以在處理觸摸事件的ACTION_MOVE時,獲取手指觸摸的x,y來得到當前拖拽到item之上的position。這里需要注意的一點是,在拖拽的過程,同一個item的position是不會變的,除非調(diào)用了Adapter的notifyDataSetChanged,position才會重新計算。比如position為2的item,在拖拽的過程無論怎么動畫移動位置,他的position都是2,知道一次拖拽結束,ActionUp的時候,會調(diào)用notifyDataSetChanged
GridView
@Override
public boolean onTouchEvent(MotionEvent ev)
{
case MotionEvent.ACTION_MOVE:
if (mDragStarted)
{
// ......
int position = pointToPosition((int) ev.getX(), (int) ev.getY());
// ......
}
break;
}
如何實現(xiàn)動畫
一個item需要水平以及垂直需要移動的距離可以事先先計算出來,其實水平距離不管怎么樣一定會是GridView一個單元格的寬度加上水平間距,垂直距離無論如何都是一個單元格的高度加上垂直距離,寬度非常好取,高度的話,這里默認item 的高度和單元格的高度相同。
GridViewSortAdapter
View view = mGridView.getChildAt(0); mTranslateX = view.getWidth() + mHorizontalSpace; mTranslateY = view.getHeight() + mVerticalSpace;
當拖拽到其他item之上時,開始動畫
SortGridView
if (position != AdapterView.INVALID_POSITION && !((GridViewSortAdapter) getAdapter()).isInAnimation())
{
Log.d(TAG, "position = " + position);
((GridViewSortAdapter) getAdapter()).swap(position);
}
GridSortAdapter
public void swap(int position)
{
mAnimatorSetList.clear();
int r_p = mPositionList.indexOf(position);
Log.d(TAG, "r_p = " + r_p);
if (mCurrentHideItemPosition < r_p)
{
for (int i = mCurrentHideItemPosition + 1; i <= r_p; i++)
{
View v = mGridView.getChildAt(mPositionList.get(i));
if (i % mColsNum == 0 && i > 0)
{
startMoveAnimation(v, v.getTranslationX() + mTranslateX * (mColsNum - 1), v.getTranslationY() -
mTranslateY);
}
else
{
startMoveAnimation(v, v.getTranslationX() - mTranslateX, 0);
}
}
}
else if (mCurrentHideItemPosition > r_p)
{
for (int i = r_p; i < mCurrentHideItemPosition; i++)
{
View v = mGridView.getChildAt(mPositionList.get(i));
if ((i + 1) % mColsNum == 0)
{
startMoveAnimation(v, v.getTranslationX() - mTranslateX * (mColsNum - 1), v.getTranslationY() + mTranslateY);
}
else
{
startMoveAnimation(v, v.getTranslationX() + mTranslateX, 0);
}
}
}
resetPositionList();
int value = mPositionList.get(mStartHideItemPosition);
if (mStartHideItemPosition < r_p)
{
mPositionList.add(r_p + 1, value);
mPositionList.remove(mStartHideItemPosition);
}
else if (mStartHideItemPosition > r_p)
{
mPositionList.add(r_p, value);
mPositionList.remove(mStartHideItemPosition + 1);
}
mCurrentHideItemPosition = r_p;
}
public boolean isInAnimation()
{
return mInAnimation;
}
private void resetPositionList()
{
mPositionList.clear();
for (int i = 0; i < mGridView.getChildCount(); i++)
{
mPositionList.add(i);
}
}
private void startMoveAnimation(View myView, float x, float y)
{
AnimatorSet set = new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(myView, "translationX", myView.getTranslationX(), x),
ObjectAnimator.ofFloat(myView, "translationY", myView.getTranslationY(), y)
);
set.addListener(new Animator.AnimatorListener()
{
@Override
public void onAnimationStart(Animator animator)
{
mInAnimation = true;
}
@Override
public void onAnimationEnd(Animator animator)
{
mInAnimation = false;
}
@Override
public void onAnimationCancel(Animator animator)
{
}
@Override
public void onAnimationRepeat(Animator animator)
{
}
});
mAnimatorSetList.add(set);
set.setDuration(150).start();
}
這里我主要解釋一下代碼中 mPositionList這個列表的作用,之前說過一次拖拽的時候,item的position是不會變化的。
假設有一組數(shù)據(jù)
a b c d
e f g h
i j k l
此時mPositionList的內(nèi)容就是 0 1 2 3 4 5 6 7 8 9 10 11 12
現(xiàn)在將c拖拽到g上,拖拽完成之后的數(shù)據(jù)應該是,未釋放手指
a b d e
f g c h
i j k l
此時mPositionList的內(nèi)容就是 0 1 2 4 5 6 7 3 8 9 10 11 12
緊接著,繼續(xù)拖拽c到e上,你會發(fā)現(xiàn)調(diào)用pointToPosition方法得到的position是5,但是e現(xiàn)在的索引是4
因此你只需要調(diào)用
mPositionList.indexOf(pointToPosition(x,y))
就能得到真實的item的position
其他
如果把GridView的列數(shù)變成1那么似曾相識啊

gridviewex.gif
源碼地址
以上所述是小編給大家介紹的Android 仿網(wǎng)易新聞客戶端分類排序功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
- Android項目實戰(zhàn)之仿網(wǎng)易新聞的頁面(RecyclerView )
- Android實現(xiàn)仿網(wǎng)易新聞的頂部導航指示器
- Android實現(xiàn)仿網(wǎng)易新聞主界面設計
- Android實現(xiàn)網(wǎng)易新聞客戶端首頁效果
- Android實現(xiàn)類似網(wǎng)易新聞選項卡動態(tài)滑動效果
- Android模擬實現(xiàn)網(wǎng)易新聞客戶端
- Android實現(xiàn)網(wǎng)易新聞客戶端側滑菜單(1)
- Android組件DrawerLayout仿網(wǎng)易新聞v4.4側滑菜單
- Android實現(xiàn)網(wǎng)易新聞客戶端側滑菜單(2)
- Android仿網(wǎng)易新聞圖片詳情下滑隱藏效果示例代碼
相關文章
使用RecyclerView添加Header和Footer的方法
RecyclerView雖然作為ListView的替代者有著較好的性能提升,但是ListView的一些常用功能卻沒有提供,比如我們平時會經(jīng)常用到的addHeaderView,addFooterView,既然RecyclerView沒有提供這個方法,我們應該如何為列表添加頭部和底部呢,接下來通過本文給大家介紹2016-03-03
Android開發(fā)技巧之在a標簽或TextView控件中單擊鏈接彈出Activity(自定義動作)
a標簽以及TextView自動識別的特殊文本(網(wǎng)址、電話號、Email等),這些都可以通過單擊來觸發(fā)不同的動作;但如果讀者想在單擊鏈接時執(zhí)行任意自定義的動作,那么將要介紹的一定是你想要的了2013-01-01
Android中LayoutInflater.inflater()的正確打開方式
這篇文章主要給大家介紹了關于Android中LayoutInflater.inflater()的正確打開方式,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧2018-12-12
Android中CountDownTimer 實現(xiàn)倒計時功能
本篇文章主要介紹了Android中CountDownTimer 實現(xiàn)倒計時功能,CountDownTimer 是android 自帶的一個倒計時類,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-05-05
Android 6.0以上權限拒絕打開權限設置界面的解決方法
今天小編就為大家分享一篇Android 6.0以上權限拒絕打開權限設置界面的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07
Android Studio 升級到3.0后輸入法中文狀態(tài)下無法選詞的終極解決方案
這篇文章主要介紹了 AndroidStudio 升級到3.0后輸入法中文狀態(tài)下無法選詞的解決方案,需要的朋友可以參考下2017-11-11

