文章目录
【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>
总结:
以上代码是全部代码,如果需要源代码可私信,谢谢!