新闻频道管理的炫酷实现
新聞?lì)l道管理的炫酷實(shí)現(xiàn)
自定義GridLayout控件,可以在新聞咨詢類APP中的管理頁(yè)面使用到,也可以應(yīng)用在類別管理中,總之,可以幫助我們?cè)O(shè)計(jì)更加規(guī)范和炫酷的手機(jī)頁(yè)面。
新聞?lì)恆pp是最常見的應(yīng)用之一,而頻道管理又是其必不可少的功能,該自定義控件不僅可以帶我們實(shí)現(xiàn)炫酷的頻道管理功能,還可以讓我們學(xué)習(xí)如何使用Android拖拽框架實(shí)現(xiàn)我們想要的多種功能,以及讓我們對(duì)自定義控件會(huì)有更多的理解。
知識(shí)點(diǎn)
GridLayout的使用
- 從Google官方文檔學(xué)習(xí)GridLayout的功能以及用法
- 使用GridLayout實(shí)現(xiàn)子控件排列顯示
View的拖拽功能實(shí)現(xiàn)
- 通過(guò)查看Google文檔,學(xué)會(huì)調(diào)用view的拖拽方法
- 拖拽事件的處理
- 使用View的拖拽框架實(shí)現(xiàn)實(shí)現(xiàn)頻道切換位置效果
自定義GridLayout控件
自定義GridLayout控件,實(shí)現(xiàn)拖拽功能,繼而實(shí)現(xiàn)頻道管理操作
Rect類的使用
使用Rect類確定被觸摸到的子控件
新聞?lì)l道管理的多種實(shí)現(xiàn)
實(shí)現(xiàn)類似于網(wǎng)易新聞?lì)l道管理有幾種方式
實(shí)現(xiàn)方案1:使用兩個(gè)GridView實(shí)現(xiàn),這是比較早的一種解決方案,比較復(fù)雜,具體可以參考 Android 高仿 頻道管理—-網(wǎng)易、今日頭條、騰訊視頻
實(shí)現(xiàn)方案2:使用兩個(gè)RecyclerView或ListView實(shí)現(xiàn),這種實(shí)現(xiàn)方式好于于方案1
實(shí)現(xiàn)方案3:使用一個(gè)RecyclerView實(shí)現(xiàn),這是我目前見過(guò)的比較好的方式,貌似比網(wǎng)易新聞等客戶端的要流暢,具體可以參考:高仿網(wǎng)易新聞欄目動(dòng)畫效果 、 使用ItemTouchHelper高效地實(shí)現(xiàn) 今日頭條 、網(wǎng)易新聞 的頻道排序、移動(dòng)
實(shí)現(xiàn)方案4:使用兩個(gè)GridLayout實(shí)現(xiàn),也就是本文要介紹的方式
拖拽
長(zhǎng)按item開始拖拽
private View.OnLongClickListener longClickListener = new View.OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {//長(zhǎng)按時(shí),開始拖拽操作,顯示出陰影//被拖拽的視圖其實(shí)就是v參數(shù)dragedView = v;v.startDrag(null, new View.DragShadowBuilder(v), null, 0);v.setEnabled(false);// v.startDragAndDrop(null, new View.DragShadowBuilder(v), null, 0);return false;}};拖拽方法參數(shù)說(shuō)明
- startDragAndDrop() api24
- startDrag(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flag)
參數(shù)1:ClipData data 拖拽過(guò)程中可以transferred的數(shù)據(jù),可以為空
參數(shù)2:DragShadowBuilder shadowBuilder,拖拽陰影效果創(chuàng)建者
參數(shù)3:Object myLocalState,拖拽狀態(tài)
參數(shù)4:int flag,可以控制拖拽操作的flag,未定義,傳0即可
拖拽監(jiān)聽
private View.OnDragListener dragListener = new View.OnDragListener() {/*** ACTION_DRAG_STARTED:當(dāng)拖拽操作執(zhí)行時(shí),就會(huì)執(zhí)行一次* DragEvent.ACTION_DRAG_ENDED:當(dāng)拖拽事件結(jié)束,手指抬起時(shí),就是執(zhí)行一次* DragEvent.ACTION_DRAG_ENTERED:當(dāng)手指進(jìn)入設(shè)置了拖拽監(jiān)聽的控件范圍內(nèi)的瞬間執(zhí)行一次* DragEvent.ACTION_DRAG_EXITED:當(dāng)手指離開設(shè)置了拖拽監(jiān)聽的控件范圍內(nèi)的瞬間執(zhí)行一次* DragEvent.ACTION_DRAG_LOCATION:當(dāng)手指在設(shè)置了拖拽監(jiān)聽的控件范圍內(nèi),移動(dòng)時(shí),實(shí)時(shí)會(huì)執(zhí)行,執(zhí)行N次* DragEvent.ACTION_DROP:當(dāng)手指在設(shè)置了拖拽監(jiān)聽的控件范圍內(nèi)松開時(shí),執(zhí)行一次*** @param v 當(dāng)前監(jiān)聽拖拽事件的view(其實(shí)就是mGridLayout)* @param event 拖拽事件* @return*/@Overridepublic boolean onDrag(View v, DragEvent event) {String dragEventAction = getDragEventAction(event);System.out.println(dragEventAction);// Rect rect = new Rect();// rect.contains()switch (event.getAction()) {//當(dāng)拖拽事件開始時(shí),創(chuàng)建出與子控件對(duì)應(yīng)的矩形數(shù)組case DragEvent.ACTION_DRAG_STARTED:initRects();break;case DragEvent.ACTION_DRAG_LOCATION://手指移動(dòng)時(shí),實(shí)時(shí)判斷觸摸是否進(jìn)入了某一個(gè)子控件int touchIndex = getTouchIndex(event);//說(shuō)明觸摸點(diǎn)進(jìn)入了某一個(gè)子控件,判斷被拖拽的視圖與進(jìn)入的子控件對(duì)象不是同一個(gè)的時(shí)候才進(jìn)行刪除添加操作if (touchIndex > -1&&dragedView != null&&dragedView != mGridLayout.getChildAt(touchIndex)) {mGridLayout.removeView(dragedView);mGridLayout.addView(dragedView,touchIndex);}break;case DragEvent.ACTION_DRAG_ENDED://拖拽事件結(jié)束后,讓被拖拽的view設(shè)置為可用,否則背景變紅,并且長(zhǎng)按事件會(huì)失效if (dragedView != null) {dragedView.setEnabled(true);}break;}return true;}};DragEvent
| ACTION_DRAG_STARTED | 當(dāng)拖拽操作執(zhí)行時(shí),就會(huì)執(zhí)行一次 |
| DragEvent.ACTION_DRAG_ENDED | 當(dāng)拖拽事件結(jié)束,手指抬起時(shí),就是執(zhí)行一次 |
| DragEvent.ACTION_DRAG_ENTERED | 當(dāng)手指進(jìn)入設(shè)置了拖拽監(jiān)聽的控件范圍內(nèi)的瞬間執(zhí)行一次 |
| DragEvent.ACTION_DRAG_EXITED | 當(dāng)手指離開設(shè)置了拖拽監(jiān)聽的控件范圍內(nèi)的瞬間執(zhí)行一次 |
| DragEvent.ACTION_DRAG_LOCATION | 當(dāng)手指在設(shè)置了拖拽監(jiān)聽的控件范圍內(nèi),移動(dòng)時(shí),實(shí)時(shí)會(huì)執(zhí)行,執(zhí)行N次 |
| DragEvent.ACTION_DROP | 當(dāng)手指在設(shè)置了拖拽監(jiān)聽的控件范圍內(nèi)松開時(shí),執(zhí)行一次 |
當(dāng)拖拽事件開始時(shí),創(chuàng)建出與子控件對(duì)應(yīng)的矩形數(shù)組
private Rect[] mRects;private void initRects() {mRects = new Rect[mGridLayout.getChildCount()];for (int i = 0; i < mGridLayout.getChildCount(); i++) {View childView = mGridLayout.getChildAt(i);//創(chuàng)建與每個(gè)子控件對(duì)應(yīng)矩形對(duì)象Rect rect = new Rect(childView.getLeft(), childView.getTop(), childView.getRight(), childView.getBottom());mRects[i] = rect;}}手指移動(dòng)時(shí),實(shí)時(shí)判斷觸摸是否進(jìn)入了某一個(gè)子控件
private int getTouchIndex(DragEvent event) {//遍歷所有的數(shù)組,如果包含了當(dāng)前的觸摸點(diǎn)返回索引即可for (int i = 0; i < mRects.length; i++) {Rect rect = mRects[i];if (rect.contains((int)event.getX(), (int)event.getY())) {return i;}}return -1;}是否允許拖拽
public void setAllowDrag(boolean allowDrag) {this.allowdrag = allowDrag;if (this.allowdrag) {this.setOnDragListener(odl);} else {this.setOnDragListener(null);}}設(shè)置列數(shù)和動(dòng)畫
//初始化方法 private void init() {// android:columnCount="4"// android:animateLayoutChanges="true"this.setColumnCount(columnCount);this.setLayoutTransition(new LayoutTransition()); }DragGridlayout
public class DragGridlayout extends GridLayout{private static final int columnCount = 4;//列數(shù)private boolean isAllowDrag;//記錄當(dāng)前控件是否可以進(jìn)行拖拽操作public DragGridlayout(Context context) {this(context,null);}public DragGridlayout(Context context, AttributeSet attrs) {this(context, attrs,0);}public DragGridlayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}/* static SparseArray<String> dragEventType = new SparseArray<>();static{dragEventType.put(DragEvent.ACTION_DRAG_STARTED, "STARTED");dragEventType.put(DragEvent.ACTION_DRAG_ENDED, "ENDED");dragEventType.put(DragEvent.ACTION_DRAG_ENTERED, "ENTERED");dragEventType.put(DragEvent.ACTION_DRAG_EXITED, "EXITED");dragEventType.put(DragEvent.ACTION_DRAG_LOCATION, "LOCATION");dragEventType.put(DragEvent.ACTION_DROP, "DROP");}public static String getDragEventAction(DragEvent de){return dragEventType.get(de.getAction());}*///初始化方法private void init() {// android:columnCount="4"// android:animateLayoutChanges="true"this.setColumnCount(columnCount);this.setLayoutTransition(new LayoutTransition());}public void setItems(List<String> items) {for (String item : items) {addItem(item);}}public void addItem(String content, int index) {TextView tv = newItemView();tv.setText(content);addView(tv,index);}public void addItem(String content) {TextView tv = newItemView();tv.setText(content);addView(tv);}private TextView newItemView() {TextView tv = new TextView(getContext());int margin = dip2px(5);tv.setBackgroundResource(R.drawable.selector_tv_bg);GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams();layoutParams.width = getResources().getDisplayMetrics().widthPixels/4 - 2*margin;//寬為屏幕寬的4分之一layoutParams.height = dip2px(25);layoutParams.setMargins(margin,margin,margin,margin);tv.setGravity(Gravity.CENTER);tv.setLayoutParams(layoutParams);if (isAllowDrag) {//給條目設(shè)置長(zhǎng)按點(diǎn)擊事件tv.setOnLongClickListener(mLongClickListener);} else {tv.setOnLongClickListener(null);}//設(shè)置條目的點(diǎn)擊事件tv.setOnClickListener(onClickListener);return tv;}/** dip轉(zhuǎn)換px */public int dip2px(int dip) {final float scale = getResources().getDisplayMetrics().density;return (int) (dip * scale + 0.5f);}private View dragedView;//被拖拽的視圖private View.OnLongClickListener mLongClickListener = new View.OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {//長(zhǎng)按時(shí),開始拖拽操作,顯示出陰影//被拖拽的視圖其實(shí)就是v參數(shù)dragedView = v;v.startDrag(null, new View.DragShadowBuilder(v), null, 0);v.setEnabled(false);//v.startDragAndDrop(null, new View.DragShadowBuilder(v), null, 0); // api24return true;}};private OnClickListener onClickListener = new OnClickListener() {@Overridepublic void onClick(View v) {if(onDragItemClickListener != null){onDragItemClickListener.onDragItemClick((TextView) v);}}};public void setAllowDrag(boolean isAllowDrag) {this.isAllowDrag = isAllowDrag;if (this.isAllowDrag) {this.setOnDragListener(mDragListener);} else {this.setOnDragListener(null);}}private View.OnDragListener mDragListener = new View.OnDragListener() {/*** ACTION_DRAG_STARTED:當(dāng)拖拽操作執(zhí)行時(shí),就會(huì)執(zhí)行一次* DragEvent.ACTION_DRAG_ENDED:當(dāng)拖拽事件結(jié)束,手指抬起時(shí),就是執(zhí)行一次* DragEvent.ACTION_DRAG_ENTERED:當(dāng)手指進(jìn)入設(shè)置了拖拽監(jiān)聽的控件范圍內(nèi)的瞬間執(zhí)行一次* DragEvent.ACTION_DRAG_EXITED:當(dāng)手指離開設(shè)置了拖拽監(jiān)聽的控件范圍內(nèi)的瞬間執(zhí)行一次* DragEvent.ACTION_DRAG_LOCATION:當(dāng)手指在設(shè)置了拖拽監(jiān)聽的控件范圍內(nèi),移動(dòng)時(shí),實(shí)時(shí)會(huì)執(zhí)行,執(zhí)行N次* DragEvent.ACTION_DROP:當(dāng)手指在設(shè)置了拖拽監(jiān)聽的控件范圍內(nèi)松開時(shí),執(zhí)行一次** @param v 當(dāng)前監(jiān)聽拖拽事件的view(其實(shí)就是mGridLayout)* @param event 拖拽事件* @return*/@Overridepublic boolean onDrag(View v, DragEvent event) {switch (event.getAction()) {//當(dāng)拖拽事件開始時(shí),創(chuàng)建出與子控件對(duì)應(yīng)的矩形數(shù)組case DragEvent.ACTION_DRAG_STARTED:initRects();break;case DragEvent.ACTION_DRAG_LOCATION://手指移動(dòng)時(shí),實(shí)時(shí)判斷觸摸是否進(jìn)入了某一個(gè)子控件int touchIndex = getTouchIndex(event);//說(shuō)明觸摸點(diǎn)進(jìn)入了某一個(gè)子控件,判斷被拖拽的視圖與進(jìn)入的子控件對(duì)象不是同一個(gè)的時(shí)候才進(jìn)行刪除添加操作if (touchIndex > -1 && dragedView != null && dragedView != DragGridlayout.this.getChildAt(touchIndex)) {DragGridlayout.this.removeView(dragedView);DragGridlayout.this.addView(dragedView,touchIndex);}break;case DragEvent.ACTION_DRAG_ENDED://拖拽事件結(jié)束后,讓被拖拽的view設(shè)置為可用,否則背景變紅,并且長(zhǎng)按事件會(huì)失效if (dragedView != null) {dragedView.setEnabled(true);}break;}return true;}};//手指移動(dòng)時(shí),實(shí)時(shí)判斷觸摸是否進(jìn)入了某一個(gè)子控件private int getTouchIndex(DragEvent event) {//遍歷所有的數(shù)組,如果包含了當(dāng)前的觸摸點(diǎn)返回索引即可for (int i = 0; i < mRects.length; i++) {Rect rect = mRects[i];if (rect.contains((int)event.getX(), (int)event.getY())) {return i;}}return -1;}//當(dāng)拖拽事件開始時(shí),創(chuàng)建出與子控件對(duì)應(yīng)的矩形數(shù)組private Rect[] mRects;private void initRects() {mRects = new Rect[this.getChildCount()];for (int i = 0; i < this.getChildCount(); i++) {View childView = this.getChildAt(i);//創(chuàng)建與每個(gè)子控件對(duì)應(yīng)矩形對(duì)象Rect rect = new Rect(childView.getLeft(), childView.getTop(), childView.getRight(), childView.getBottom());mRects[i] = rect;}}private OnDragItemClickListener onDragItemClickListener;public interface OnDragItemClickListener{public void onDragItemClick(TextView tv);}public void setOnDragItemClickListener(OnDragItemClickListener onDragItemClickListener) {this.onDragItemClickListener = onDragItemClickListener;} }MainActivity
布局文件
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayout android:id="@+id/activity_main"xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><Button android:layout_width="match_parent"android:layout_height="36dp"android:gravity="center_vertical"android:onClick="addItem"android:text="添加條目"android:textColor="?android:attr/textColorPrimary"/><com.github.draggridlayout.DragGridlayout android:id="@+id/selectedChannel"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="16dp"android:layout_marginTop="16dp"/><TextView android:id="@+id/textView"android:layout_width="match_parent"android:layout_height="36dp"android:background="?attr/colorButtonNormal"android:gravity="center_vertical"android:padding="5dp"android:text="點(diǎn)擊選擇頻道"android:textColor="?android:attr/textColorPrimary"/><com.github.draggridlayout.DragGridlayout android:id="@+id/unSelectedChannel"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="16dp"/></LinearLayout></android.support.v4.widget.NestedScrollView>代碼實(shí)現(xiàn)
public class MainActivity extends AppCompatActivity {private DragGridlayout mSelectedChannel;private DragGridlayout mUnSelectedChannel;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);initViews();initData();initEvent();}private void initViews() {setContentView(R.layout.activity_main);mSelectedChannel = (DragGridlayout) findViewById(R.id.selectedChannel);mUnSelectedChannel = (DragGridlayout) findViewById(R.id.unSelectedChannel);mSelectedChannel.setAllowDrag(true);mUnSelectedChannel.setAllowDrag(true);}private void initData() {List<String> selectedChannel = new ArrayList<>();selectedChannel.add("頭條");...mSelectedChannel.setItems(selectedChannel);List<String> unSelectedChannel = new ArrayList<>();unSelectedChannel.add("NBA");...mUnSelectedChannel.setItems(unSelectedChannel);}public void initEvent(){//設(shè)置條目點(diǎn)擊監(jiān)聽mSelectedChannel.setOnDragItemClickListener(new DragGridlayout.OnDragItemClickListener() {@Overridepublic void onDragItemClick(TextView tv) {//移除點(diǎn)擊的條目,把條目添加到下面的GridlayoutmSelectedChannel.removeView(tv);//移除是需要時(shí)間,不能直接添加mUnSelectedChannel.addItem(tv.getText().toString(),0);}});mUnSelectedChannel.setOnDragItemClickListener(new DragGridlayout.OnDragItemClickListener() {@Overridepublic void onDragItemClick(TextView tv) {//移除點(diǎn)擊的條目,把條目添加到上面的GridlayoutmUnSelectedChannel.removeView(tv);//移除是需要時(shí)間,不能直接添加mSelectedChannel.addItem(tv.getText().toString());}});}private int index = 0;public void addItem(View view) {mSelectedChannel.addItem("頻道" + index++,0);}}源代碼
https://github.com/JackChan1999/DragGridLayout
總結(jié)
以上是生活随笔為你收集整理的新闻频道管理的炫酷实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: TextureView+MediaPla
- 下一篇: 自定义歌词展示控件