先上结果:
一、bug分析
这个项目一共遇到两个问题:
1.Imageview使用混合图片的时候state_checked这个属性在代码中setSelected(true)是无效的,具体原因没有找到
于是我就用state_pressed这个属性替代
但是又产生了一个问题,按压按钮是会变色了,松手后又弹回原来的颜色,于是我就把点击事件改为触摸事件
这样一来触摸就可以直接捕获到状态。
2.text使用setTextcolor(R.color.xxx)的时候变色失效
原因是setTextcolor接受的是16进制的数据,而不是资源id,如果要用需要调用getColor方法
二、实现效果
好了,话不多说,开始正文
· 在activity中添加viewpager2控件(旧版sdk可能需要在build.gradle中添加对应的控件包)
· 准备八张图片(阿里巴巴矢量图标库),在drawable中创建四组图片资源文件(点击改变图片背景)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/faxian_on" android:state_pressed="true"/>
<item android:drawable="@drawable/faxian" />
</selector>
· 创建导航栏
<?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:orientation="horizontal">
<LinearLayout
android:id="@+id/weixin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
//添加混合图片weixinliaotian_fix
<ImageView
android:id="@+id/weixin_button"
android:layout_gravity="center_horizontal"
android:background="@drawable/weixinliaotian_fix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="微信"
android:id="@+id/t1"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:id="@+id/tongxunlu"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<ImageView
android:id="@+id/tongxunlu_button"
android:layout_gravity="center_horizontal"
android:background="@drawable/tongxunlu_fix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/t2"
android:layout_gravity="center_horizontal"
android:text="通讯录"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:id="@+id/faxian"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<ImageView
android:id="@+id/faxian_button"
android:layout_gravity="center_horizontal"
android:background="@drawable/faxian_fix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/t3"
android:layout_gravity="center_horizontal"
android:text="发现"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:id="@+id/wode"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<ImageView
android:id="@+id/wode_button"
android:layout_gravity="center_horizontal"
android:background="@drawable/wode_fix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/t4"
android:layout_gravity="center_horizontal"
android:text="我"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
· 在活动界面引入导航栏
· 在activity中获取viewpager2对象并设置adapter
viewPager2 = findViewById(R.id.vp2);
viewpageradapter = new viewpageradapter(getSupportFragmentManager(), getLifecycle(), fragmentList);
viewPager2.setAdapter(viewpageradapter);
· 创建Fragment(就只有一个text控件)
· 创建适配器 (继承FragmentStateAdapter而不是FragmentPagerAdapter)
FragmentPageAdapter和FragmentPageStateAdapter的区别:
FragmentPageAdapter在每次切换页面的的时候,是将Fragment进行分离,适合页面较少的Fragment使用以保存一些内存,对系统内存不会多大影响
FragmentPageStateAdapter在每次切换页面的时候,是将Fragment进行回收,适合页面较多的Fragment使用,这样就不会消耗更多的内存
public class viewpageradapter extends FragmentStateAdapter {
//接收fragment
List<Fragment> fragmentList;
public viewpageradapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle,List<Fragment> fragmentList) {
super(fragmentManager, lifecycle);
this.fragmentList=fragmentList;
}
@NonNull
@Override
public Fragment createFragment(int position) {
//返回对应位置的fragment界面
return fragmentList.get(position);
}
@Override
public int getItemCount() {
//返回fragment数量
return fragmentList.size();
}
}
· 重点来了 实现fragment和导航栏按钮的联动效果
要用到这个回调函数:实现三个方法,我们需要实现的只有改变页面的方法
viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
/**
* 这个方法负责侦听页面的偏移量
* @param position 当前显示的第一页的位置索引 如果 positionOffset 非零,则页面位置+1 将可见。
* @param positionOffset [0, 1) 中的值指示从页面位置的偏移量。
* @param positionOffsetPixels 以像素为单位的值,指示与位置的偏移量。
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
//解决getcolor的版本问题(可以删掉)
@RequiresApi(api = Build.VERSION_CODES.M)
//这个方法负责切换页面 poistion从0开始
@Override
public void onPageSelected(int position) {
changetab(position);
}
//当滚动状态改变时调用。 用于发现用户何时开始拖动、何时开始假拖动、何时寻呼机自动稳定到当前页面,或何时完全停止/空闲。
@Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
}
});
}
这个是按钮触摸事件的触发方法
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
changetab(view.getId());
return false;
}
这个方法负责接收两种不同的参数,一是当前的滚动页面位置,二是按钮id
页面滚动调用按钮设置为按压状态,按钮按下将页面滚动至对应页面,从而实现联动效果。
//上面两个引用为了设置文字颜色
@RequiresApi(api = Build.VERSION_CODES.M)
@SuppressLint("ResourceAsColor")
private void changetab(int position) {
//每次滚动之前把按压状态设置为false 文字颜色设置为初始颜色
current.setPressed(false);
currenttext.setTextColor(MainActivity.this.getColor(black));
switch (position) {
case R.id.weixin:
//传入按钮id不用保存当前状态/颜色的原因是 页面滚动会自动调用回调函数触发上面三个方法,也就是说会再次调用这个changetab方法,不过传入对应的position值
viewPager2.setCurrentItem(0);
break;
case 0:
//设置文字颜色
t1.setTextColor(MainActivity.this.getColor(green));
//设置imageview为按压状态
weixin_button.setPressed(true);
//保存当前状态/颜色
current = weixin_button;
currenttext = t1;
break;
case R.id.tongxunlu:
viewPager2.setCurrentItem(1);
break;
case 1:
t2.setTextColor(MainActivity.this.getColor(green));
tongxunlu_button.setPressed(true);
current = tongxunlu_button;
currenttext = t2;
break;
case R.id.faxian:
viewPager2.setCurrentItem(2);
break;
case 2:
t3.setTextColor(MainActivity.this.getColor(green));
faxian_button.setPressed(true);
current = faxian_button;
currenttext = t3;
break;
case R.id.wode:
viewPager2.setCurrentItem(3);
break;
case 3:
t4.setTextColor(MainActivity.this.getColor(green));
wode_button.setPressed(true);
current = wode_button;
currenttext = t4;
break;
}
}
三、源码
源码如下:
Maintivity
public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
List<Fragment> fragmentList;//fragment集合 传参给adapter
viewpageradapter viewpageradapter;
ViewPager2 viewPager2;
LinearLayout weixin, tongxunlu, faxian, wode;
ImageView weixin_button, tongxunlu_button, faxian_button, wode_button, current;//current记录当前imageview状态
TextView t1, t2, t3, t4, currenttext;//currenttext记录当前text状态
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
weixin.setOnTouchListener(this);
tongxunlu.setOnTouchListener(this);
faxian.setOnTouchListener(this);
wode.setOnTouchListener(this);
viewPager2 = findViewById(R.id.vp2);
viewpageradapter = new viewpageradapter(getSupportFragmentManager(), getLifecycle(), fragmentList);
viewPager2.setAdapter(viewpageradapter);
viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onPageSelected(int position) {
changetab(position);
}
@Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
}
});
}
@RequiresApi(api = Build.VERSION_CODES.M)
@SuppressLint("ResourceAsColor")
private void changetab(int position) {
current.setPressed(false);
currenttext.setTextColor(MainActivity.this.getColor(black));
switch (position) {
case R.id.weixin:
viewPager2.setCurrentItem(0);
Log.d("TAG", "changetab:weixin按压 " + weixin_button.isPressed());
break;
case 0:
t1.setTextColor(MainActivity.this.getColor(green));
weixin_button.setPressed(true);
Log.d("TAG", "changetab:weixin滑动 " + weixin_button.isPressed());
current = weixin_button;
currenttext = t1;
break;
case R.id.tongxunlu:
viewPager2.setCurrentItem(1);
Log.d("TAG", "changetab:tongxunlu按压 " + tongxunlu_button.isPressed());
break;
case 1:
t2.setTextColor(MainActivity.this.getColor(green));
tongxunlu_button.setPressed(true);
Log.d("TAG", "changetab:tongxunlu滑动 " + tongxunlu.isPressed());
current = tongxunlu_button;
currenttext = t2;
break;
case R.id.faxian:
viewPager2.setCurrentItem(2);
Log.d("TAG", "changetab:faxian按压 " + faxian_button.isPressed());
break;
case 2:
t3.setTextColor(MainActivity.this.getColor(green));
faxian_button.setPressed(true);
Log.d("TAG", "changetab:faxian滑动 " + faxian_button.isPressed());
current = faxian_button;
currenttext = t3;
break;
case R.id.wode:
viewPager2.setCurrentItem(3);
Log.d("TAG", "changetab:wode按压 " + wode_button.isPressed());
break;
case 3:
t4.setTextColor(MainActivity.this.getColor(green));
wode_button.setPressed(true);
Log.d("TAG", "changetab:wode滑动 " + wode_button.isPressed());
current = wode_button;
currenttext = t4;
break;
}
}
@RequiresApi(api = Build.VERSION_CODES.M)
@SuppressLint("ResourceAsColor")
private void init() {
fragmentList = new ArrayList<>();
fragmentList.add(BlankFragment.newInstance("微信"));
fragmentList.add(BlankFragment.newInstance("联系人"));
fragmentList.add(BlankFragment.newInstance("发现"));
fragmentList.add(BlankFragment.newInstance("我的"));
weixin = findViewById(R.id.weixin);
tongxunlu = findViewById(R.id.tongxunlu);
faxian = findViewById(R.id.faxian);
wode = findViewById(R.id.wode);
weixin_button = findViewById(R.id.weixin_button);
tongxunlu_button = findViewById(R.id.tongxunlu_button);
faxian_button = findViewById(R.id.faxian_button);
wode_button = findViewById(R.id.wode_button);
t1 = findViewById(R.id.t1);
t2 = findViewById(R.id.t2);
t3 = findViewById(R.id.t3);
t4 = findViewById(R.id.t4);
weixin_button.setPressed(true);
t1.setTextColor(MainActivity.this.getColor(green));
current = weixin_button;
currenttext = t1;
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
changetab(view.getId());
return false;
}
}
Maintivity layout
<?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=".MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/vp2"
android:layout_height="0dp"
android:layout_weight="11"
android:layout_width="match_parent"/>
<include
layout="@layout/navigation"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"/>
</LinearLayout>
viewpagerAdapter
```java
public class viewpageradapter extends FragmentStateAdapter {
List<Fragment> fragmentList;
public viewpageradapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle,List<Fragment> fragmentList) {
super(fragmentManager, lifecycle);
this.fragmentList=fragmentList;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return fragmentList.get(position);
}
@Override
public int getItemCount() {
return fragmentList.size();
}
}
viewpagerAdapter layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context=".BlankFragment">
<TextView
android:id="@+id/ft1"
android:text="nice"
android:layout_centerInParent="true"
android:textSize="50sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
navigation(只有布局)
<?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:orientation="horizontal">
<LinearLayout
android:id="@+id/weixin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<ImageView
android:id="@+id/weixin_button"
android:layout_gravity="center_horizontal"
android:background="@drawable/weixinliaotian_fix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="微信"
android:id="@+id/t1"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:id="@+id/tongxunlu"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<ImageView
android:id="@+id/tongxunlu_button"
android:layout_gravity="center_horizontal"
android:background="@drawable/tongxunlu_fix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/t2"
android:layout_gravity="center_horizontal"
android:text="通讯录"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:id="@+id/faxian"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<ImageView
android:id="@+id/faxian_button"
android:layout_gravity="center_horizontal"
android:background="@drawable/faxian_fix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/t3"
android:layout_gravity="center_horizontal"
android:text="发现"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:id="@+id/wode"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<ImageView
android:id="@+id/wode_button"
android:layout_gravity="center_horizontal"
android:background="@drawable/wode_fix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/t4"
android:layout_gravity="center_horizontal"
android:text="我"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
图片和color就不放了