【Android企业级开发案例分享】仿西瓜视频主页面框架,自定义GridLayout条目长按拖拽换位,条目点击删除添加,GreenDao数据持久化,Tab标签顺序实时刷新,Tab标签选中自字体变大变色

本文分享了一篇关于Android企业级开发的案例,详细介绍了如何仿制西瓜视频主页面,包括自定义GridLayout实现条目长按拖拽换位、点击删除添加功能,使用GreenDao进行数据持久化,以及Tab标签顺序实时刷新和选中时字体大小颜色变化等技术要点。
摘要由CSDN通过智能技术生成

【Android企业级开发案例分享】仿西瓜视频,仿今日头条主页面框架,自定义GridLayout条目长按拖拽换位,条目点击删除添加,GreenDao数据持久化,Tab标签顺序实时刷新,Tab标签选中字体变大变色

案例效果

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

代码实现:

DrigGridItemLayout类(自定义的GridLayout条目拖拽的类)

package com.example.customview2.widget;

import android.animation.LayoutTransition;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.DragEvent;
import android.view.Gravity;
import android.view.View;
import android.widget.GridLayout;
import android.widget.TextView;

import com.example.customview2.R;
import com.example.customview2.base.App;
import com.example.customview2.callback.IItemClick;
import com.example.customview2.db.PinDaoInfoDao;
import com.example.customview2.entity.PinDaoInfo;

import java.util.List;

public class DragGridItemLayout extends GridLayout {
    private Context mContext;
    private int mMargin = 15;
    private int mWidth;
    private int itemCount = 4;
    private Rect[] mRects;
    private View mDragedView;
    private IItemClick mItemClick;
    private boolean mIsDragable;

    //接口回调
    public void setOnItemClickListenner(IItemClick itemClickListenner) {
        this.mItemClick = itemClickListenner;
    }


    public DragGridItemLayout(Context context) {
        this(context, null);
    }

    public DragGridItemLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DragGridItemLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        init();
    }

    private void init() {
        setColumnCount(itemCount);
        setLayoutTransition(new LayoutTransition());

        //屏幕的宽度
        mWidth = mContext.getResources().getDisplayMetrics().widthPixels;
    }


    //1.先调用
    // 参数为true  代表条目能长按 |条目能拖拽    参数为false  条目不能长按|不能拖拽
    public void setDragable(boolean isDragabled) {  //专门处理是否能拖拽和长按
        this.mIsDragable = isDragabled;
        //每个条目拖拽事件
        if (mIsDragable) {
            setOnDragListener(dragListenner);
        } else {
            setOnDragListener(null);
        }
        for (int i = 0; i < getChildCount(); i++) {
            TextView textView = (TextView) getChildAt(i);
            if (mIsDragable) {
                textView.setOnLongClickListener(new OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View v) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                            //1.参数 向拖拽条目传递的数据对象,2.条目拖拽构建的阴影对象 3.拖拽条目的状态
                            v.startDragAndDrop(null, new DragShadowBuilder(v), null, 0);
                        else
                            v.startDrag(null, new DragShadowBuilder(v), null, 0);
                        mDragedView = v;
                        return false;
                    }
                });
            } else {
                textView.setOnLongClickListener(null);
            }

        }

    }


    //2.再调用    第二个参数 true代表添加这个条目到GridLayout的最后面,如果是false代表添加条目到GridLayout最上面
    //  这个方法三件事 第一件事 添加View   第二件事 设置条目长按事件   第三件事设置条目单击事件
    public void addItems(List<PinDaoInfo> infos, boolean isLast) {
        for (PinDaoInfo info : infos) {
            String name = info.getmName();
            setItem(name, isLast);
        }
    }


    public void setItem(String name, boolean isLast) {
        final TextView itemView = new TextView(mContext);
        itemView.setBackgroundResource(R.drawable.item_bg);
        itemView.setPadding(mMargin, mMargin + 15, mMargin, mMargin + 15);
        itemView.setText(name);
        GridLayout.LayoutParams tvParams = new GridLayout.LayoutParams();
        //设置TextView的外边距
        tvParams.setMargins(mMargin, mMargin, mMargin, mMargin);
        //设置TextView的控件的宽度 =  (整个父容器的宽度- 4个条目的两边外边距的宽度)/4
        tvParams.width = (mWidth - mMargin * 2 * itemCount) / itemCount;
        itemView.setLayoutParams(tvParams);
        itemView.setGravity(Gravity.CENTER);
        if (isLast)
            addView(itemView);
        else
            addView(itemView, 0);
        if (mIsDragable) {
            //设置条目的长按监听
            itemView.setOnLongClickListener(new OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                        //1.参数 向拖拽条目传递的数据对象,2.条目拖拽构建的阴影对象 3.拖拽条目的状态
                        v.startDragAndDrop(null, new DragShadowBuilder(v), null, 0);
                    else
                        v.startDrag(null, new DragShadowBuilder(v), null, 0);
                    mDragedView = v;
                    return false;
                }
            });
        } else {
            itemView.setOnLongClickListener(null);
        }

        //每个条目单击监听
        itemView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mItemClick != null) {
                    mItemClick.getClickView(v);
                }
            }
        });
    }


    // 实时监听 当拖拽的条目被拖拽到目标条目的范围内,将被拖拽的条目删除,然后将被拖拽的那个条目插入到目标条目索引位置上
    // 这样就完成了拖拽换位
    //
    private OnDragListener dragListenner = new OnDragListener() {
        @Override
        public boolean onDrag(View v, DragEvent event) {
            switch (event.getAction()) {
                //开始拖拽条目的时候执行1次
                case DragEvent.ACTION_DRAG_STARTED:
                    initRects();
                    break;
                //进入拖拽区域范围内执行1次
                case DragEvent.ACTION_DRAG_ENTERED:
                    break;
                //在拖拽区域范围内一直拖拽一直执行   如何判断A条目被拖拽到B条目范围内了呢?
                case DragEvent.ACTION_DRAG_LOCATION:
                    //目标索引值
                    int index = getTargetIndex(event);
                    View targetView = getChildAt(index);
                    if (index > 1 && mDragedView != targetView) {
                        //拖拽换位
                        removeView(mDragedView);
                        addView(mDragedView, index);
                    }
                    break;
                //拖出拖拽范围会执行一次
                case DragEvent.ACTION_DRAG_EXITED:
                    break;
                //不管在拖拽范围外还是在拖拽范围内结束拖拽都会执行一次
                case DragEvent.ACTION_DRAG_ENDED:
                    break;
                //在拖拽范围内结束拖拽会执行一次
                case DragEvent.ACTION_DROP:
                    for (int i = 0; i < getChildCount(); i++) {
                        TextView childAt = (TextView) getChildAt(i);
                        String str = childAt.getText() + "";
                        Log.e("ccccc", "" + str);
                        PinDaoInfo unique = App.getmPinDaoInfoDao().queryBuilder().
                                where(PinDaoInfoDao.Properties.MName.eq(str)).build().unique();

                        // 因为数据库的ID是从1开始的 就算赋值为0了,还是从1开始的,所以可以将实体Bean对象新添加个字段 这个字段就是每个对象的索引值 从0开始
                        //数据库中id改不了可以改实体bean中的索引值
                        unique.setMPosition(i);
                        unique.setMName(str);
                        App.getmPinDaoInfoDao().update(unique);

                    }
                    break;

            }
            return true;
        }
    };

    private int getTargetIndex(DragEvent event) {
        int index = -1;
        int x = (int) event.getX();
        int y = (int) event.getY();
        for (int i = 0; i < mRects.length; i++) {
            Rect rect = mRects[i];
            if (rect.contains(x, y)) {
                index = i;
            }
        }
        return index;
    }

    private void initRects() {
        int childCount = getChildCount();
        mRects = new Rect[childCount];
        for (int i = 0; i < childCount; i++) {
            TextView textView = (TextView) getChildAt(i);
            Rect rect = new Rect(textView.getLeft(), textView.getTop(),
                    textView.getRight(), textView.getBottom());
            mRects[i] = rect;
        }
    }
}

需要的Activity
HomeActivity为Home页面,GridLayoutActivity为条目拖拽页面
HomeActivity类如下:

package com.example.customview2.ui.activity;

import android.graphics.Color;
import android.net.LinkAddress;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;

import com.example.customview2.R;
import com.example.customview2.adapter.HomePagerAdapter;
import com.example.customview2.ui.fragment.HomeFragment;
import com.google.android.material.bottomnavigation.BottomNavigationView;

import java.util.ArrayList;
import java.util.List;

public class HomeActivity extends AppCompatActivity implements BottomNavigationView.
        OnNavigationItemSelectedListener {
    private BottomNavigationView mBottomView;
    private ViewPager mViewPager;
    private MenuItem mItem;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        init();
    }

    private void init() {
        mViewPager = findViewById(R.id.viewpager);
        mBottomView = findViewById(R.id.bottom_navigation_view);
        List<HomeFragment> fragments = getFragments();
        HomePagerAdapter adapter = new HomePagerAdapter(getSupportFragmentManager(), fragments);
        mViewPager.setAdapter(adapter);
        mBottomView.setItemIconTintList(null);//除去黑框
        mBottomView.setOnNavigationItemSelectedListener(this);
    }

    //注意:BotomNavigationView 里面最大只能放5个条目
    private List<HomeFragment> getFragments() {
        List<HomeFragment> list = new ArrayList<HomeFragment>();
        //获取bottomNavigationView中所有条目的个数
        int ix = mBottomView.getMenu().size();
        for (int i = 0; i < ix; i++) {
            list.add(new HomeFragment(i));
        }
        return list;
    }

    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        this.mItem = item;
        switch (item.getItemId()) {
            case R.id.action_home:
                naviPager(0);
                break;
            case R.id.action_fangyingting:
                naviPager(1);
                break;
            case R.id.action_live:
                naviPager(2);
                break;
            case R.id.action_mine:
                naviPager(3);
                break;
        }
        return true;
    }

    private void naviPager(int i) {
        mViewPager.setCurrentItem(i);
    }
}

GridLayoutActivity类如下:

package com.example.customview2.ui.activity;

import android.database.Cursor;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.example.customview2.R;
import com.example.customview2.base.App;
import com.example.customview2.callback.IItemClick;
import com.example.customview2.db.PinDaoInfoDao;
import com.example.customview2.entity.PinDaoInfo;
import com.example.customview2.widget.DragGridItemLayout;

import org.greenrobot.greendao.query.WhereCondition;

import java.util.ArrayList;
import java.util.List;

public class GridLayoutActivity extends AppCompatActivity {
    private DragGridItemLayout mDragLayout, mUnDragLayout;
    private TextView mtv_edit, mtv_pindao, mtv_close;
    private boolean mFlag;
    private boolean isLast = true;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_grid);
        initView();
    }

    private void initView() {
        mDragLayout = findViewById(R.id.grid_drag_item);
        mUnDragLayout = findViewById(R.id.grid_undrag_item);
        mtv_edit = findViewById(R.id.tv_edittext);
        mtv_pindao = findViewById(R.id.tv_enterpindao);
        mtv_close = findViewById(R.id.drag_grid_close_tv);
        mtv_edit.setOnClickListener(clickListenner);
        mtv_close.setOnClickListener(clickListenner);

        //上半部分  条目可拖拽部分
        mDragLayout.setDragable(false);
        //按照索引值升序查询数据库
        List<PinDaoInfo> dragList = App.getmPinDaoInfoDao().queryBuilder().where(PinDaoInfoDao.Properties.
                MFlag.eq(0)).orderAsc(PinDaoInfoDao.Properties.MPosition).build().list();
        mDragLayout.addItems(dragList, true);

        for (int i = 0; i < dragList.size(); i++) {
            Log.e("vccccccc", dragList.get(i).getMName() + "==================" + dragList.get(i).getmPosition());
        }


        //默认情况 1.点击上半部分的条目,关闭当前页面,跳转到Home页面,然后定位到这个条目索引值对应的tab标签,重新进入拖拽页面,刚才点击的那个条目中的文本变成红色
        mDragLayout.setOnItemClickListenner(new IItemClick() {
            @Override
            public void getClickView(View view) {
                close();
                //传递选中的条目的文本传到HomeFragment里面   sp;
                String itemStr = ((TextView) view).getText() + "";
                Log.e("CCCCCCCCCCCCC", itemStr + "============点击的条目是=====" + itemStr);
                App.getSp().edit().putString("itemStr", itemStr).commit();
            }
        });
        String selectedText = App.getSp().getString("tabSelected", "");
        //回显选中的TextView的颜色
        for (int i = 0; i < dragList.size(); i++) {
            String name = dragList.get(i).getmName();
            if (selectedText.equals(name)) {
                Log.e("AAAAAAAA", "选中的tab对应的索引值是:" + i);
                View view = mDragLayout.getChildAt(i);
                if (view instanceof TextView) {
                    TextView textView = (TextView) view;
                    textView.setTextColor(Color.RED);
                    //拖拽页面 回显的时候存一次
                    App.getSp().edit().putString("itemStr", textView.getText() + "").commit();
                }
            }
        }


        // File , ContentProvider ,SQLite,网络存储,SharedPreference
        //下半部分 ,条目不可拖拽部分
        mUnDragLayout.setDragable(false);
        //不能拖拽部分查询数据库并排序
        List<PinDaoInfo> unDragList = App.getmPinDaoInfoDao().queryBuilder().where(PinDaoInfoDao.Properties.
                MFlag.eq(1)).orderAsc(PinDaoInfoDao.Properties.
                MPosition).build().list();

        for (PinDaoInfo pinDaoInfo : unDragList) {
            Log.e("DDDDDDDDDD11111111111111DDDDDDDDD", pinDaoInfo.getMPosition() + "+=======下半部分不可拖拽部分=======" + pinDaoInfo.getmName());
        }

        mUnDragLayout.addItems(unDragList, isLast);
        //默认情况,点击下半部分的条目,将下半部分点击的那个条目删除,然后下半部分删除的条目添加到上半部分的最后面
        mUnDragLayout.setOnItemClickListenner(new IItemClick() {
            @Override
            public void getClickView(View view) {
                //下半部分删除
                mUnDragLayout.removeView(view);
                String text = ((TextView) view).getText() + "";
                //下半部分数据库删除
                PinDaoInfo unique = App.getmPinDaoInfoDao().queryBuilder().where(PinDaoInfoDao.Properties.MName.eq(text)).
                        build().unique();
                if (unique != null)
                    App.getmPinDaoInfoDao().delete(unique);
                else {
                    Log.e("hasjashasas", "删除的对象为空了。。。。。。。。");
                }

                //上半部分添加到最后面
                mDragLayout.setItem(text, isLast);
                //上半部分数据库添加
                String name = unique.getmName();


                List<PinDaoInfo> list1 = App.getmPinDaoInfoDao().queryBuilder().where(PinDaoInfoDao.
                        Properties.MFlag.eq(0)).orderDesc
                        (PinDaoInfoDao.Properties.MPosition).build().list();
                if (list1 != null && list1.size() > 0) {
                    Integer maxPosition = list1.get(0).getmPosition();
                    //上半部分最大的索引值+1
                    PinDaoInfo info = new PinDaoInfo(name, 0, maxPosition + 1);
                    App.getmPinDaoInfoDao().insert(info);
                }
            }
        });


    }

    private void close() {
        finish();
        overridePendingTransition(R.anim.close_in, R.anim.close_out);
    }

    private View.OnClickListener clickListenner = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.tv_edittext:
                    if (!mFlag) {
                        mtv_edit.setText("完成");
                        mtv_pindao.setText("按住拖动可以排序");
                        //TODO tv变成完成的时候 让上半部分条目可以拖拽
                        mDragLayout.setDragable(true);
                        //TODO  开始 tv变成完成的时候 点击上半部分的条目,删除点击的那个条目,然后将上半部分删除的条目添加到下半部分的最上面
                        mDragLayout.setOnItemClickListenner(new IItemClick() {
                            @Override
                            public void getClickView(View view) {

                                String item_str = ((TextView) view).getText() + "";

                                //TODO 数据库删除上半部分点击的那个条目  上半部分删除
                                mDragLayout.removeView(view);
                                //电影
                                PinDaoInfo unique = App.getmPinDaoInfoDao().queryBuilder().
                                        where(PinDaoInfoDao.Properties.MName.eq(item_str)).build().
                                        unique();
                                App.getmPinDaoInfoDao().delete(unique);


                                //TODO 数据库添加上半部分删除的那个条目  下 n半部分添加到最上面
                                List<PinDaoInfo> list = App.getmPinDaoInfoDao().queryBuilder().where
                                        (PinDaoInfoDao.Properties.MFlag.eq(1)).
                                        orderAsc(PinDaoInfoDao.Properties.MPosition).build().list();
                                if (list != null && list.size() > 0) {
                                    PinDaoInfo ifo = list.get(0);
                                    if (ifo.getmPosition() > 0) {
                                        //下半部分最小索引值-1
                                        int minPosition = ifo.getmPosition() - 1;
                                        mUnDragLayout.setItem(item_str, !isLast);
                                        PinDaoInfo info = new PinDaoInfo(unique.getMName(), 1, minPosition);
                                        App.getmPinDaoInfoDao().insert(info);
                                    }

                                }

                                for (PinDaoInfo pinDaoInfo : list) {
                                    Log.e("DDDDDDDDD222222222222DDDDDDDDDD", pinDaoInfo.getMPosition() + "+=======下半部分不可拖拽部分=======" + pinDaoInfo.getmName());
                                }
                            }
                        });
                        //TODO 结束 tv变成完成的时候 点击上半部分的条目,删除点击的那个条目,然后将上半部分删除的条目添加到下半部分的最上面

                        mFlag = true;
                    } else {
                        mtv_edit.setText("编辑");
                        mtv_pindao.setText("点击进入频道");
                        //TODO tv变成 编辑的时候 让上半部分条目不可以拖拽
                        mDragLayout.setDragable(false);
                        mFlag = false;
                    }
                    break;
                case R.id.drag_grid_close_tv:
                    close();
                    break;
            }
        }
    };


}

需要的实体Bean类PinDaoInfoDao如下:

package com.example.customview2.entity;

import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Property;
import org.greenrobot.greendao.annotation.Transient;

@Entity
public class PinDaoInfo {
    @Id(autoincrement = true)
    private Long mId;
    @Property(nameInDb = "name")  //在数据库里面这个字段名是 name
    private String mName;
    @Property(nameInDb = "flag")//在数据库里面这个字段名是 flag
    private int mFlag; //0代表能拖拽 1代表不能拖拽
    @Property(nameInDb = "position")
    private Integer mPosition;


    public Integer getmPosition() {
        return mPosition;
    }

    public void setmPosition(Integer mPosition) {
        this.mPosition = mPosition;
    }

    @Generated(hash = 1804718167)
    public PinDaoInfo(Long mId, String mName, int mFlag, Integer mPosition) {
        this.mId = mId;
        this.mName = mName;
        this.mFlag = mFlag;
        this.mPosition = mPosition;
    }

    public PinDaoInfo(String mName, int mFlag, Integer mPosition) {
        this.mName = mName;
        this.mFlag = mFlag;
        this.mPosition = mPosition;
    }

    public PinDaoInfo() {
    }

    public PinDaoInfo(String mName) {
        this.mName = mName;
    }

    public PinDaoInfo(String mName, int mFlag) {
        this.mName = mName;
        this.mFlag = mFlag;
    }

    public PinDaoInfo(Long mId, String mName, int mFlag) {
        this.mId = mId;
        this.mName = mName;
        this.mFlag = mFlag;
    }

    @Override
    public String toString() {
        return "PinDaoInfo{" +
                "mId=" + mId +
                ", mName='" + mName + '\'' +
                ", mFlag=" + mFlag +
                ", mPosition=" + mPosition +
                '}';
    }

    public String getmName() {
        return mName;
    }

    public void setmName(String mName) {
        this.mName = mName;
    }

    public Long getMId() {
        return this.mId;
    }

    public void setMId(Long mId) {
        this.mId = mId;
    }

    public String getMName() {
        return this.mName;
    }

    public void setMName(String mName) {
        this.mName = mName;
    }

    public int getMFlag() {
        return this.mFlag;
    }

    public void setMFlag(int mFlag) {
        this.mFlag = mFlag;
    }

    public Integer getMPosition() {
        return this.mPosition;
    }

    public void setMPosition(Integer mPosition) {
        this.mPosition = mPosition;
    }
}

HomeFragment类如下:

package com.example.customview2.ui.fragment;

import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;

import com.example.customview2.R;
import com.example.customview2.adapter.HFragmentPagerAdapter;
import com.example.customview2.base.App;
import com.example.customview2.db.PinDaoInfoDao;
import com.example.customview2.entity.PinDaoInfo;
import com.example.customview2.ui.activity.GridLayoutActivity;
import com.google.android.material.tabs.TabLayout;
import java.util.ArrayList;
import java.util.List;

public class HomeFragment extends Fragment implements View.OnClickListener, TabLayout.OnTabSelectedListener {
    private int mType;
    private LayoutInflater mInflater;
    private ViewGroup mViewGroup;

    public HomeFragment(int type) {
        this.mType = type;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        this.mInflater = inflater;
        this.mViewGroup = container;
        switch (mType) {
            case 0:
                return getView(R.layout.fragment_home);
            case 1:
                return getView(R.layout.fragment_projection_hall);
            case 2:
                return getView(R.layout.fragment_release);
            case 3:
                return getView(R.layout.fragment_mime);
        }
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        initView(view);
        super.onViewCreated(view, savedInstanceState);
    }

    private ViewPager mViewPager;
    private TabLayout mTabLayout;
    private TextView mTextView;
    private List<PinDaoInfo> mList;

    private void initView(View view) {
        switch (mType) {
            case 0:
                initSubFragmentView(view);
                break;
            case 1:
                break;
            case 2:
                break;
            case 3:
                break;

        }

    }

    @Override
    public void onStart() {
        super.onStart();
        switch (mType) {
            case 0:
                //TODO 按照索引值升序重新查询数据库----------------------------
                mList = App.getmPinDaoInfoDao().queryBuilder().where(PinDaoInfoDao.Properties.
                        MFlag.eq(0)).orderAsc(PinDaoInfoDao.Properties.MPosition).build().list();
                List<SubHomeFragment> fragments = getSubFragment();
                HFragmentPagerAdapter adapter = new HFragmentPagerAdapter
                        (getChildFragmentManager(), mList, fragments);
                mViewPager.setAdapter(adapter);
                mTabLayout.setupWithViewPager(mViewPager);
                mTextView.setOnClickListener(this);
                // TODO 用的自定义的tab
                //设置tab默认的文本大小和选中的tab文本的大小  只能设置一次
                setTabTextSize();
                //TODO 按照索引值升序重新查询数据库----------------------------
                String itemStr = App.getSp().getString("itemStr", "");
                int position = 0;
                if (TextUtils.isEmpty(itemStr)) {
                    position = 0;
                } else {
                    for (int i = 0; i < mList.size(); i++) {
                        if (itemStr.equals(mList.get(i).getmName())) {
                            position = i;
                        }
                    }
                }
                mViewPager.setCurrentItem(position);
                mTabLayout.getTabAt(position).getCustomView().setSelected(true);
                TextView textView = ((TextView) mTabLayout.getTabAt(position).getCustomView());
                textView.setTextColor(Color.RED);
                textView.setTextSize(23);
                //后边每次滑动tab的时候 设置选中tab中的文字为红色,未选中的文字为黑色
                mTabLayout.addOnTabSelectedListener(this);
                App.getSp().edit().putString("tabSelected", textView.getText() + "").commit();

                break;
            case 1:
                break;
            case 2:
                break;
            case 3:
                break;

        }

    }

    private void initSubFragmentView(View view) {
        mViewPager = view.findViewById(R.id.home_subfragment_viewpager);
        mTabLayout = view.findViewById(R.id.home_subfragment_tablayout);
        mTextView = view.findViewById(R.id.home_subfragment_tv);

        mList = App.getmPinDaoInfoDao().queryBuilder().where(PinDaoInfoDao.Properties.MFlag.eq(0)).
                orderAsc(PinDaoInfoDao.Properties.MPosition).
                build().list();
        List<SubHomeFragment> fragments = getSubFragment();
        HFragmentPagerAdapter adapter = new HFragmentPagerAdapter
                (getChildFragmentManager(), mList, fragments);
        mViewPager.setAdapter(adapter);
        mTabLayout.setupWithViewPager(mViewPager);
        mTextView.setOnClickListener(this);
        // TODO 用的自定义的tab
        //设置tab默认的文本大小和选中的tab文本的大小  只能设置一次
        setTabTextSize();
    }


    private void setTabTextSize() {
        for (int i = 0; i < mTabLayout.getTabCount(); i++) {
            TabLayout.Tab tab = mTabLayout.getTabAt(i);
            //自定义每个tab标签 然后设置给每个tab
            tab.setCustomView(getTabView(i));
        }


    }

    //自定义每个Tab标签
    private View getTabView(int i) {
        View view = LayoutInflater.from(getActivity()).inflate(R.layout.tab_layout, null);
        TextView textView = view.findViewById(R.id.tab_tv);
        textView.setText(mList.get(i).getmName());
        return view;
    }

    private List<SubHomeFragment> getSubFragment() {
        List<SubHomeFragment> fragments = new ArrayList<SubHomeFragment>();
        for (int i = 0; i < mList.size(); i++) {
            fragments.add(new SubHomeFragment(i));
        }
        return fragments;
    }

    private View getView(int layoutId) {
        return mInflater.inflate(layoutId,
                mViewGroup, false);
    }

    @Override
    public void onClick(View v) {
        //TODO 从上往下打开拖拽Activity   默认情况下没有动画
        startActivity(new Intent(getActivity(), GridLayoutActivity.class));
        //需要加Activiyt打开动画  1.出来的动画(打开的动画)   2.出去的动画(关闭的动画)
        getActivity().overridePendingTransition(R.anim.enter_anim, R.anim.exit_anim);
    }

    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        Log.e("ghasgshasa", "onTabSelected====1111=====tab被选中了" + tab.getPosition());
        View customView = tab.getCustomView();
        if (customView != null && customView instanceof TextView) {
            ((TextView) customView).setTextSize(23);
            ((TextView) customView).setTextColor(Color.RED);
            App.getSp().edit().putString("tabSelected", ((TextView) customView).getText() + "").commit();
        }
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {
        Log.e("ghasgshasa", "onTabSelected====222=====tab没有被选中了" + tab.getPosition());
        View customView = tab.getCustomView();
        if (customView != null && customView instanceof TextView) {
            ((TextView) customView).setTextSize(18);
            ((TextView) customView).setTextColor(Color.BLACK);
        }
    }

    @Override
    public void onTabReselected(TabLayout.Tab tab) {
        Log.e("ghasgshasa", "onTabReselected====33333=====");
    }
}


SubHomeFragment类如下:

package com.example.customview2.ui.fragment;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.example.customview2.R;

public class SubHomeFragment extends Fragment {
    private LayoutInflater mInflater;
    private ViewGroup mViewGroup;
    private int mType;

    public SubHomeFragment(int type) {
        this.mType = type;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        this.mInflater = inflater;
        this.mViewGroup = container;
        switch (mType) {
            case 0:
                return getView(R.layout.subfragment_guanzhu);
            case 1:
                return getView(R.layout.subfragment_tuijian);
            case 2:
                return getView(R.layout.subfragment_yingshi);
            case 3:
                return getView(R.layout.subfragment_dianshiju);
            case 4:
                return getView(R.layout.subfragment_movie);
            case 5:
                return getView(R.layout.subfragment_xiaodianying);
            case 6:
                return getView(R.layout.subfragment_youxi);
        }
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    private View getView(int layoutId) {
        return mInflater.inflate(layoutId, mViewGroup, false);
    }
}

需要的适配器类为f分别为HomePagerAdapter(是HomeActivity中四个Fragment和ViewPager的适配器)和HFragmentPagerAdapter类(是HomeFragment中多很多小tab对应的ViewPager的适配器)
HomePagerAdapter如下:

package com.example.customview2.adapter;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;

import com.example.customview2.ui.fragment.HomeFragment;

import java.util.List;

public class HomePagerAdapter extends FragmentPagerAdapter {
    private List<HomeFragment> mList;

    public HomePagerAdapter(@NonNull FragmentManager fm,
                            List<HomeFragment> fragments) {
        super(fm);
        this.mList = fragments;
    }

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

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

HFragmentPagerAdapter类如下:

package com.example.customview2.adapter;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;

import com.example.customview2.entity.PinDaoInfo;
import com.example.customview2.ui.fragment.SubHomeFragment;

import java.util.List;

public class HFragmentPagerAdapter extends FragmentPagerAdapter {
    private List<PinDaoInfo> mTabs;
    private List<SubHomeFragment> list;

    public HFragmentPagerAdapter
            (@NonNull FragmentManager fm, List<PinDaoInfo> mTabs,
             List<SubHomeFragment> fragments) {
        super(fm);
        this.mTabs = mTabs;
        this.list = fragments;
    }

    @NonNull
    @Override
    public Fragment getItem(int position) {
        return list.get(position);
    }

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

    @Nullable
    @Override
    public CharSequence getPageTitle(int position) {
        return mTabs.get(position).getmName();
    }
}

App类如下:

package com.example.customview2.base;

import android.app.Application;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;

import com.example.customview2.db.DaoMaster;
import com.example.customview2.db.PinDaoInfoDao;
import com.example.customview2.entity.PinDaoInfo;

import java.util.ArrayList;
import java.util.List;


public class App extends Application {
    private static SharedPreferences mSp;
    private static PinDaoInfoDao mPinDaoInfoDao;

    @Override
    public void onCreate() {
        mSp = getSharedPreferences("config", MODE_PRIVATE);
        initGreenDao();
        initDatas();
        super.onCreate();
    }

    private void initDatas() {
        boolean isFirstEnter = mSp.getBoolean("isFirstEnter", true);
        if (isFirstEnter) {
            mSp.edit().putBoolean("isFirstEnter", false).commit();
            gtetPinDaoInfos();
        }
    }

    //第一种(用数据库).先查询数据库,看里面有没有数据,如果有就不处理,如果没有数据,就往里面插入数据
    // 第二种(用sp).每次安装的时候会执行一次欢迎页面,以后每次打开这个app都不走欢迎页面而是直接跳转到主页面
    //每次安装这个app的时候只插入一次数据就行了,  每次安装这个app的时候插入数据 ,以后操作的时候再也不插入数据了
    private void initGreenDao() {
        DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.
                DevOpenHelper(this, "greendao.db", null);
        SQLiteDatabase db = devOpenHelper.getWritableDatabase();
        DaoMaster daoMaster = new DaoMaster(db);
        mPinDaoInfoDao = daoMaster.newSession().getPinDaoInfoDao();
    }


    public static SharedPreferences getSp() {
        if (mSp != null)
            return mSp;
        return null;
    }

    public static PinDaoInfoDao getmPinDaoInfoDao() {
        if (mPinDaoInfoDao != null)
            return mPinDaoInfoDao;
        return null;
    }
  //可以用for循环简化
    private void gtetPinDaoInfos() {
        List<PinDaoInfo> list = new ArrayList<PinDaoInfo>();
        list.add(new PinDaoInfo("关注", 0, 0));
        list.add(new PinDaoInfo("推荐", 0, 1));
        list.add(new PinDaoInfo("电影", 0, 2));
        list.add(new PinDaoInfo("小视频", 0, 3));
        list.add(new PinDaoInfo("游戏", 0, 4));
        list.add(new PinDaoInfo("电视剧", 0, 5));
        list.add(new PinDaoInfo("校园", 0, 6));
        list.add(new PinDaoInfo("VLOG", 0, 7));
        list.add(new PinDaoInfo("农人", 0, 8));
        list.add(new PinDaoInfo("美食", 0, 9));
        list.add(new PinDaoInfo("宠物", 0, 10));
        list.add(new PinDaoInfo("搞笑", 0, 11));
        list.add(new PinDaoInfo("懂车帝", 0, 12));
        list.add(new PinDaoInfo("体育", 0, 13));
        list.add(new PinDaoInfo("手工", 0, 14));
        list.add(new PinDaoInfo("娱乐", 0, 15));
        list.add(new PinDaoInfo("文化", 0, 16));
        list.add(new PinDaoInfo("科技", 0, 17));
        list.add(new PinDaoInfo("财经", 0, 18));
        list.add(new PinDaoInfo("广场舞", 0, 19));
        list.add(new PinDaoInfo("旅游", 0, 20));
        list.add(new PinDaoInfo("NBA", 0, 21));
        list.add(new PinDaoInfo("军事", 0, 22));
        list.add(new PinDaoInfo("影视", 1, 23));
        list.add(new PinDaoInfo("抗疫", 1, 24));
        list.add(new PinDaoInfo("音乐", 1, 25));
        list.add(new PinDaoInfo("综艺", 1, 26));
        list.add(new PinDaoInfo("在家上课", 1, 27));
        list.add(new PinDaoInfo("游戏剧场", 1, 28));
        list.add(new PinDaoInfo("小康", 1, 29));
        //只需要插入一个集合
        mPinDaoInfoDao.insertInTx(list);
    }

}

接口回调类IItemClick如下:

package com.example.customview2.callback;

import android.view.View;

public interface IItemClick {
    void getClickView(View view);
}

自定义的不能滑动的NeteViewPager类如下:

package com.example.customview2.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.viewpager.widget.ViewPager;

public class NeteViewPager extends ViewPager {

    public NeteViewPager(@NonNull Context context) {
        super(context);
    }

    public NeteViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    //ViewPager不拦截(事件可以向子View传递)  保证让子View能获取这个事件
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return false;
    }


    //ViewPager本身将事件消费掉
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return true;
    }

    //onIntercepTouchEvent返回false , onTouchEvent()返回true 最外层的ViewPager滑动不了?
    // 只是 onTouchEvent返回true 最外层ViewPager能慢慢滑动?

    //原因: 老版本的ViewPager中只重写onTouchEvnet()返回true是可以的,
    // 新版的ViewPager将ViewPager的滑动监听换成了 addOnPageLitenner,


}

activity_home.xml布局如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ui.activity.HomeActivity">


    <com.example.customview2.widget.NeteViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_above="@id/bottom_navigation_view"
        android:layout_weight="1" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_navigation_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFFFFFFF"
        app:itemTextColor="@drawable/item_text_bg"
        app:labelVisibilityMode="labeled"
        app:menu="@menu/bottom_navigation_item" />
</LinearLayout>

activity_grid.xml布局如下:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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"
    android:background="#FFFFFF"
    android:scrollbars="none"
    tools:context=".ui.activity.GridLayoutActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="15dp">

            <TextView
                android:id="@+id/drag_grid_close_tv"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:layout_alignParentRight="true"
                android:layout_marginTop="15dp"
                android:layout_marginRight="5dp"
                android:gravity="center"
                android:text="×"
                android:textSize="30dp"
                android:textStyle="normal" />
        </RelativeLayout>

        <!--我最喜欢 频道管理-->
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="40dp"
            android:gravity="center_vertical">

            <TextView
                android:id="@+id/tv_mylike"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:text="我最喜欢"
                android:textSize="20sp"
                android:textStyle="bold"></TextView>


            <TextView
                android:id="@+id/tv_enterpindao"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginTop="3dp"
                android:layout_toRightOf="@+id/tv_mylike"
                android:text="点击进入频道"></TextView>


            <TextView
                android:id="@+id/tv_edittext"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_marginTop="3dp"
                android:layout_marginRight="18dp"
                android:text="编辑"
                android:textColor="#DD0000"
                android:textSize="16sp"
                android:textStyle="normal"></TextView>
        </RelativeLayout>

        <!--条目拖拽换位 grid-->
        <com.example.customview2.widget.DragGridItemLayout
            android:id="@+id/grid_drag_item"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp" />


        <!--我最喜欢 频道管理-->
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="40dp"
            android:gravity="center_vertical">

            <TextView
                android:id="@+id/tv_allpindao"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:text="全部频道"
                android:textSize="20sp"
                android:textStyle="bold"></TextView>


            <TextView
                android:id="@+id/tv_addpindao"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginTop="3dp"
                android:layout_toRightOf="@+id/tv_allpindao"
                android:text="点击添加频道"></TextView>


        </RelativeLayout>

        <!--条目点击 grid-->
        <com.example.customview2.widget.DragGridItemLayout
            android:id="@+id/grid_undrag_item"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp" />
    </LinearLayout>


</ScrollView>

fragment_home.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#66FFFF00"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_marginTop="50dp"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/home_subfragment_tablayout"
            android:layout_width="0dp"
            android:layout_height="45dp"
            android:layout_weight="1"
            app:tabIndicator="@null"
            app:tabMode="scrollable"
            app:tabSelectedTextColor="#FF0000"
            app:tabTextColor="#000000" />

        <TextView
            android:id="@+id/home_subfragment_tv"
            android:layout_width="wrap_content"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="≡"
            android:padding="6dp"
            android:textSize="20sp"
            android:textStyle="bold"></TextView>

    </LinearLayout>


    <androidx.viewpager.widget.ViewPager
        android:id="@+id/home_subfragment_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

tab_layout.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:id="@+id/tab_tv"
    android:layout_height="wrap_content"
    android:gravity="bottom"
    android:textSize="18sp"
    android:text="哈哈"
    android:typeface="sans">

</TextView>

menu菜单文件如下:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_home"
        android:enabled="true"
        android:icon="@mipmap/ic_launcher"
        android:title="首页"
        app:showAsAction="ifRoom" />


    <item
        android:id="@+id/action_fangyingting"
        android:enabled="true"
        android:icon="@mipmap/ic_launcher"
        android:title="放映厅"
        app:showAsAction="ifRoom" />


    <item
        android:id="@+id/action_live"
        android:enabled="true"
        android:icon="@mipmap/ic_launcher"
        android:title="直播"
        app:showAsAction="ifRoom" />

    <item
        android:id="@+id/action_mine"
        android:enabled="true"
        android:icon="@mipmap/ic_launcher"
        android:title="我的"
        app:showAsAction="ifRoom" />

</menu>

anim动画配置文件close_in.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="350"
    android:fillAfter="true">

    <translate
        android:fromYDelta="0%p"
        android:toYDelta="0%p">
    </translate>
</set>

anim动画配置文件close_out.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="350"
    android:fillAfter="true">
    <translate
        android:fromYDelta="0%p"
        android:toYDelta="100%p"></translate>
</set>

anim动画配置文件enter_anim.xml.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="350"
    android:fillAfter="true">

    <translate
        android:fromYDelta="100%p"
        android:toYDelta="0%p"></translate>


</set>

anim动画配置文件exit_anim.xml.xml.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="350"
    android:fillAfter="true">
    <translate
        android:fromYDelta="0%p"
        android:toYDelta="0%p"></translate>


</set>

总结:

以上代码是全部代码,如果需要源代码可私信,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值