小白也能學會的Android應用分類訂閱功能(新聞個性化分類訂閱),學不會你打我!

相信小夥伴們都使用過分類訂閱這個功能,像CSDN APP的分類訂閱、還有各種新聞的個性化分類訂閱,今天就來實現它!具體實現功能如下:

  • 長按進入可編輯模式(可編輯,並且分類框右邊出現一個加(減)圖標)
  • 編輯模式下可以通過點擊分類進行訂閱(或取消訂閱),並且所有分類有抖動效果
  • 點擊按鈕退出編輯模式(也可以改成 退出當前頁面 或者 其他事件)
  • 退出編輯模式的同時會保存當前訂閱狀態(下次進入頁面時會顯示上次修改後的狀態)

溫馨提示:如果ListView、GridView、RecycleView一個都不會的話建議先去學一個再來學習這個,會一個都行

話不多說先上效果圖!
在這裏插入圖片描述

首先講一下實現功能的大致思路:實現這個訂閱功能主要是在於實現兩個GridView(也可以用ListView或者Recycle,這裏演示GridView)的點擊功能,首先是長按進入編輯模式,利用長按監聽對兩個GridView設置右上角小圖標以及抖動,然後是GridView的子項點擊事件的監聽,點擊其中一個的時候,先把這個加到另外那個GridView裏面去,然後移除點擊的這個,最後點擊保存是利用List的size()和for循環來保存當前GridView裏面的所有項(算是奇淫技巧吧,只會這樣了)!接下來詳細講:

XML佈局

佈局沒啥講的,就上下兩個GridView,然後加了個按鈕(簡單到沒話說)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20sp"
        android:text="已訂閱"
        android:textColor="@color/colorBlack"
        android:textSize="18sp" />

    <GridView
        android:id="@+id/grid_top"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:numColumns="4" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20sp"
            android:layout_weight="1"
            android:text="待訂閱"
            android:textColor="@color/colorBlack"
            android:textSize="18sp" />

        <Button
            android:id="@+id/btn_ok"
            android:layout_width="wrap_content"
            android:layout_height="35dp"
            android:text="完成"
            android:textSize="12sp" />
    </LinearLayout>
    
    <GridView
        android:id="@+id/grid_bottom"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:numColumns="4" />
        
</LinearLayout>
Item的佈局(GridView的Item)

這裏是一個LinearLayout裏面放了一個TextView和一個ImageView然後把它們調整成ImageView重疊在TextView右上角

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="5dp">

        <TextView
            android:id="@+id/txv_name"
            android:layout_width="80dp"
            android:layout_height="35dp"
            android:layout_marginTop="7dp"
            android:background="@drawable/txv_stroke"
            android:gravity="center"
            android:textSize="12sp" />

        <ImageView
            android:id="@+id/imv_button"
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:layout_marginLeft="-10dp"
            android:scaleType="centerCrop" />

    </LinearLayout>
    
</LinearLayout>

Adapter(GridView的適配器)

這裏只放上來一個,我寫了兩個一樣的Adapter(只有名字不一樣),如果只用一個的話很麻煩,尤其是當更新數據的時候,會出現很多小BUG(親測),當然你也可以去試試只用一個!

這裏主要講的是那個boolean值的作用,多生成一個構造方法,可以在Activity中通過實例化傳入boolean值或者不傳入實現是否顯示右上角的小圖標!(這裏是當傳入true時就會把小圖標顯示出來)

public class AdapterTopGrid extends BaseAdapter {

    Context mContext;
    List<BeanSubGrid> mList;
    boolean editMode;

    public AdapterTopGrid(Context mContext, List<BeanSubGrid> mList) {
        this.mContext = mContext;
        this.mList = mList;
        notifyDataSetChanged();
    }
    //boolean值是爲了讓右上角小圖標顯示出來
    public AdapterTopGrid(Context mContext, List<BeanSubGrid> mList, boolean editMode) {
        this.mContext = mContext;
        this.mList = mList;
        this.editMode = editMode;
        notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return mList.size();
    }

    @Override
    public Object getItem(int position) {
        return mList.get(position);
    }

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

    class ViewHolder {
        private TextView mTxvName;
        private ImageView mImvButton;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {

        ViewHolder viewHolder = new ViewHolder();
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.sub_grid_item, null);
            viewHolder.mTxvName = convertView.findViewById(R.id.txv_name);
            viewHolder.mImvButton = convertView.findViewById(R.id.imv_button);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        viewHolder.mTxvName.setText(mList.get(position).getName());
        //當Activity重新實例化Adapter並且傳入true時,才讓小圖標顯示出來
        if (editMode) {
            viewHolder.mImvButton.setImageResource(mList.get(position).getButton());
        }
        return convertView;
    }
}

JAVA後臺

在這裏首先是判斷有沒有存過數據,如果沒有則使用默認數據(第一次進入軟件),然後是GridView的長按事件,重新實例化Adpater,進入編輯模式,接着是GridView的子項點擊事件,另一個加上點擊的那個,然後移除當前點擊的(這裏注意先加後移除),然後是按鈕的點擊事件,利用for循環實現按一定規律以Key-Value的形式用SharePrefences保存數據,並且重新實例化Adapter,讓GridView變回默認狀態。

然後抖動功能的話,屬於可選功能吧,這是做了,不想要的或者想要其他效果的可以選擇刪掉那幾行代碼!不會影響其他功能的實現!

public class SubActivity extends AppCompatActivity {

    private android.widget.GridView mGridTop;
    private android.widget.Button mBtnOk;
    private android.widget.GridView mGridBottom;
    List<BeanSubGrid> mListTop;
    List<BeanSubGrid> mListBottom;
    BeanSubGrid mBeanSubGrid;
    AdapterTopGrid mAdapterTopGrid;
    AdapterBottomGrid mAdapterBottomGrid;

    private boolean mEditMode;
    private String isEmpty;

    Context mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.subscription);
        mContext = SubActivity.this;
        mGridTop = findViewById(R.id.grid_top);
        mBtnOk = findViewById(R.id.btn_ok);
        mGridBottom = findViewById(R.id.grid_bottom);

        //數據,此時判斷是否存儲過數據,沒存儲過數據就使用默認數據
        isEmpty = (String) PreferencesUtils.get(mContext, "gridTop0", "");
        if (isEmpty.isEmpty()) {
            setDataTop();
        } else {
            mListTop = new ArrayList<>();
            int size = (int) PreferencesUtils.get(mContext, "gridTop", 0);
            for (int i = 0; i < size; i++) {
                String topStr = (String) PreferencesUtils.get(mContext, "gridTop" + i, "");
                mBeanSubGrid = new BeanSubGrid();
                mBeanSubGrid.setButton(R.mipmap.img_cut);
                mBeanSubGrid.setName(topStr);
                mListTop.add(mBeanSubGrid);
            }
        }
        isEmpty = (String) PreferencesUtils.get(mContext, "gridBottom0", "");
        if (isEmpty.isEmpty()) {
            setDataBottom();
        } else {
            mListBottom = new ArrayList<>();
            int size = (int) PreferencesUtils.get(mContext, "gridBottom", 0);
            for (int i = 0; i < size; i++) {
                String bottomStr = (String) PreferencesUtils.get(mContext, "gridBottom" + i, "");
                mBeanSubGrid = new BeanSubGrid();
                mBeanSubGrid.setButton(R.mipmap.img_add);
                mBeanSubGrid.setName(bottomStr);
                mListBottom.add(mBeanSubGrid);
            }
        }

        //進入頁面默認顯示狀態
        defaultGrid();

        //長按以後進入編輯模式
        mGridTop.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                //編輯模式
                longClickGrid();
                //改爲return true,防止長按完還會觸發點擊事件
                return true;
            }
        });
        //兩個GeidView的長按事件執行的是一樣的
        mGridBottom.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                //編輯模式
                longClickGrid();
                //改爲return true,防止長按完還會觸發點擊事件
                return true;
            }
        });
        
        //點擊完成後退出編輯模式
        mBtnOk.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //把boolean值變爲false,也就是退出了編輯模式,GridView的子項單擊事件不能再執行
                mEditMode = false;
                //默認模式(不顯示右上角圖標)
                defaultGrid();
                //這裏是停止抖動
                AnimationUtils.Translater(mGridTop, 0);
                AnimationUtils.Translater(mGridBottom, 0);

                PreferencesUtils.put(mContext, "gridTop", mListTop.size());
                for (int gridTop = 0; gridTop < mListTop.size(); gridTop++) {
                    PreferencesUtils.put(mContext,"gridTop"+gridTop,mListTop.get(gridTop).getName());
                }
                PreferencesUtils.put(mContext, "gridBottom", mListBottom.size());
                for (int gridBottom = 0; gridBottom < mListBottom.size(); gridBottom++) {
        PreferencesUtils.put(mContext,"gridBottom"+gridBottom,mListBottom.get(gridBottom).getName());
                }
                
            }
        });


        //子項點擊事件處理
        mGridTop.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                if (mEditMode) {//判斷是否處於編輯模式
                    //先把點擊的加到下面
                    mBeanSubGrid = new BeanSubGrid();
                    mBeanSubGrid.setName(mListTop.get(position).getName());
                    mBeanSubGrid.setButton(R.mipmap.img_add);
                    mListBottom.add(mBeanSubGrid);
                    //再把點擊的移除
                    mListTop.remove(position);
                    //列表更新  由於兩個GridView都發生了改變,所以需要對兩個都進行更新
                    mAdapterTopGrid.notifyDataSetChanged();
                    mAdapterBottomGrid.notifyDataSetChanged();
                } else {
                    ToastUtils.Toast(mContext, "請先長按進入編輯模式!");
                }

            }
        });
        mGridBottom.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
 
                if (mEditMode) {//判斷是否處於編輯模式
                    //先把點擊的加到上面
                    mBeanSubGrid = new BeanSubGrid();
                    mBeanSubGrid.setName(mListBottom.get(position).getName());
                    mBeanSubGrid.setButton(R.mipmap.img_cut);
                    mListTop.add(mBeanSubGrid);
                    //再把點擊的移除
                    mListBottom.remove(position);
                    //列表更新 由於兩個GridView都發生了改變,所以需要對兩個都進行更新
                    mAdapterTopGrid.notifyDataSetChanged();
                    mAdapterBottomGrid.notifyDataSetChanged();
                } else {
                    ToastUtils.Toast(mContext, "請先長按進入編輯模式!");
                }

            }
        });

    }

    //編輯模式
    private void longClickGrid() {
        //boolean值變爲true,GridView的子項單擊事件可以執行了
        mEditMode = true;
        /**
        * 兩個GridView的抖動,我是寫在工具類裏,這裏可以複製出來直接用,根據方法的參數一樣傳入就行
        public static void Translater(View view, int repeatCount) {
        Animation animation = new TranslateAnimation(0, 1, 0, 1);
        animation.setDuration(200);
        animation.setRepeatCount(repeatCount);
        view.setAnimation(animation);
        }
        */
        AnimationUtils.Translater(mGridTop, -1);
        AnimationUtils.Translater(mGridBottom, -1);
        
        mAdapterTopGrid = new AdapterTopGrid(mContext, mListTop, true);
        mGridTop.setAdapter(mAdapterTopGrid);

        mAdapterBottomGrid = new AdapterBottomGrid(mContext, mListBottom, true);
        mGridBottom.setAdapter(mAdapterBottomGrid);
    }

    //默認模式
    private void defaultGrid() {
        mAdapterTopGrid = new AdapterTopGrid(mContext, mListTop);
        mGridTop.setAdapter(mAdapterTopGrid);

        mAdapterBottomGrid = new AdapterBottomGrid(mContext, mListBottom);
        mGridBottom.setAdapter(mAdapterBottomGrid);
    }

    private void setDataTop() {
        //已訂閱區域數據
        mListTop = new ArrayList<>();

        mBeanSubGrid = new BeanSubGrid();
        mBeanSubGrid.setName("軍事");
        mBeanSubGrid.setButton(R.mipmap.img_cut);
        mListTop.add(mBeanSubGrid);

        mBeanSubGrid = new BeanSubGrid();
        mBeanSubGrid.setName("娛樂");
        mBeanSubGrid.setButton(R.mipmap.img_cut);
        mListTop.add(mBeanSubGrid);
        
        mBeanSubGrid = new BeanSubGrid();
        mBeanSubGrid.setName("JAVA");
        mBeanSubGrid.setButton(R.mipmap.img_add);
        mListBottom.add(mBeanSubGrid);
    }

    private void setDataBottom() {
        //待訂閱區域數據
        mListBottom = new ArrayList<>();
        
        mBeanSubGrid = new BeanSubGrid();
        mBeanSubGrid.setName("Python");
        mBeanSubGrid.setButton(R.mipmap.img_add);
        mListBottom.add(mBeanSubGrid);

        mBeanSubGrid = new BeanSubGrid();
        mBeanSubGrid.setName("Android");
        mBeanSubGrid.setButton(R.mipmap.img_add);
        mListBottom.add(mBeanSubGrid);

        mBeanSubGrid = new BeanSubGrid();
        mBeanSubGrid.setName("IOS");
        mBeanSubGrid.setButton(R.mipmap.img_add);
        mListBottom.add(mBeanSubGrid);
    }
}

第二篇萬字文章了,感謝閱讀!有疑問或者更好的方法實現可以留言或者私信我,歡迎交流!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章