
目录
这里简单演示实现效果,实现快速开发,并没有太好的UI界面。当掌握好了知识点,再来优化界面。实现上面的效果主要用到 ViewPager2 + Fragment + BottomNavigationView
这里只有两个控件。第一个 ViewPager2,用来放 Fragment。第二个是 BottomNavigationView 实现底部导航。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/main_viewPager"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="0dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="0dp"
android:layout_marginBottom="19dp"
app:layout_constraintBottom_toTopOf="@+id/main_bottomNavigationView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/main_bottomNavigationView"
android:layout_width="0dp"
android:layout_height="78dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/main_viewPager"
app:menu="@menu/bottomnavigationitem"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
给底部导航增加菜单按钮。在 BottomNavigationView 里添加属性 app:menu="@menu/bottomnavigationitem"。在 res 目录下 New --> Directory 新建一个menu目录。在menu目录上 New --> Menu Source File 新建一个 bottomnavigationitem.xml 文件。
在bottomnavigationitem.xml 里添加一个 item 就是在 底部导航栏里添加了一个可点击的 tab 按钮。注意,item 里面的 icon 属性你可以自己找一下好看的icon,这里简单用 mipmap 里的 ic_launcher.webp 来作为 icon。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/fragment_1"
android:icon="@mipmap/ic_launcher"
android:title="T1"/>
<item
android:id="@+id/fragment_2"
android:icon="@mipmap/ic_launcher"
android:title="T2"/>
<item
android:id="@+id/fragment_3"
android:icon="@mipmap/ic_launcher"
android:title="T3"/>
<item
android:id="@+id/fragment_4"
android:icon="@mipmap/ic_launcher"
android:title="T4"/>
<item
android:id="@+id/fragment_5"
android:icon="@mipmap/ic_launcher"
android:title="T5"/>
</menu>
ViewPager2 是高级 UI。通过适配器 Adapter 来适配数据源。创建一个 MyFragmentStateAdapter.class 类,继承 FragmentStateAdapter,实现两个方法 createFragment() 和 getItemCount()。
注意:
1、ViewPager 是与 FragmentPagerAdapter 搭配的。而 FragmentPagerAdapter 继承自 PagerAdapter。而 FragmentPagerAdapter 已经被官方给废弃了。
2、ViewPager2 是与 FragmentStateAdapter 搭配的。而 FragmentStateAdapter 继承自 RecyclerView.Adapter。因此可以用到 RecyclerView 的性质,比如垂直滑动效果。
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.List;
public class MyFragmentStateAdapter extends FragmentStateAdapter {
private List<Fragment> mData;
public MyFragmentStateAdapter(FragmentActivity fragmentActivity, List<Fragment> mData) {
super(fragmentActivity);
this.mData = mData;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return mData.get(position);
}
@Override
public int getItemCount() {
return mData == null ? 0 : mData.size();
}
}
创建一个 Fragment 来作为 ViewPager2 的数据源。
public class MyFragment extends Fragment{
/**
* 的到当前Fragment 的一个实例
*/
public static MyFragment newInstance(int position){
Bundle bundle = new Bundle();
bundle.putInt("Position", position);
MyFragment fragment = new MyFragment();
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, tabIndex + "fragment" + "onCreate");
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
}
/**
* 初始化数据
*/
private List<Fragment> initData(){
mData = new ArrayList<>();
for (int i = 0; i < 5; i++) {
mData.add(MyFragment.newInstance(i));
}
return mData;
}
ViewPager2 里对页面改变的监听是 OnPageChangeCallback(); ViewPager 是 OnPageChangeListener(), 但是已经被废弃了。
BottomNavigationView.setSelectedItemId(itemID) 根据itemID 设置选中的 item。当滑动 Fragment 时,BottomNavigationView 的每个 item 也会相应的改变。做到每个Fragment 与 下面BottomNavigationView 的每个 item 绑定。
ViewPager2.OnPageChangeCallback onPageChangeCallback = new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
int itemID = R.id.fragment_1;
switch (position) {
case 0:
itemID = R.id.fragment_1;
break;
case 1:
itemID = R.id.fragment_2;
break;
case 2:
itemID = R.id.fragment_3;
break;
case 3:
itemID = R.id.fragment_4;
break;
case 4:
itemID = R.id.fragment_5;
break;
default:
break;
}
//TODO 当Fragment滑动改变时,底部的Tab也跟着改变
mBottomNavigationView.setSelectedItemId(itemID);
}
};
对于底部导航栏 item 的监听应该是 OnNavigationItemSelectedListener,但是该方法已经被 google 官方给废弃了,所以这里用 OnItemSelectedListener 来代替。
ViewPager.setCurrentItem() 方法,设置当前 Viewpager 要加载的item (Fragment),这里做到 ViewPager2 的每一个 Fragment 与 底部导航栏的每个 item 绑定。
NavigationBarView.OnItemSelectedListener onItemSelectedListener = new NavigationBarView.OnItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
// 点击Tab, 切换对应的 Fragment
switch (item.getItemId()) {
case R.id.fragment_1:
//TODO 当点击 Tab 时,ViewPager 也切换到对应的 Fragment
mViewPager.setCurrentItem(0, true);
return true;
case R.id.fragment_2:
mViewPager.setCurrentItem(1, true);
return true;
case R.id.fragment_3:
mViewPager.setCurrentItem(2, true);
return true;
case R.id.fragment_4:
mViewPager.setCurrentItem(3, true);
return true;
case R.id.fragment_5:
mViewPager.setCurrentItem(4, true);
return true;
}
return false;
}
};
MainActivity的完整代码
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import com.example.viewpager2_demo.adapter.MyFragmentStateAdapter;
import com.example.viewpager2_demo.fragment.MyFragment;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.navigation.NavigationBarView;
import java.util.ArrayList;
import java.util.List;
@RequiresApi(api = Build.VERSION_CODES.M)
public class MainActivity extends AppCompatActivity {
private ViewPager2 mViewPager;
private BottomNavigationView mBottomNavigationView;
private List<Fragment> mData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = findViewById(R.id.main_viewPager);
mBottomNavigationView = findViewById(R.id.main_bottomNavigationView);
// 设置适配器
mViewPager.setAdapter(new MyFragmentStateAdapter(this, initData()));
mViewPager.setOffscreenPageLimit(1); //设置页面缓存的个数,默认1个
//设置底部导航栏 item 点击的监听
mBottomNavigationView.setOnItemSelectedListener(onItemSelectedListener);
// 设置 ViewPager2 页面改变的监听
mViewPager.registerOnPageChangeCallback(onPageChangeCallback);
}
ViewPager2.OnPageChangeCallback onPageChangeCallback = new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
int itemID = R.id.fragment_1;
switch (position) {
case 0:
itemID = R.id.fragment_1;
Log.d("HL", "1");
break;
case 1:
itemID = R.id.fragment_2;
Log.d("HL", "2");
break;
case 2:
itemID = R.id.fragment_3;
Log.d("HL", "3");
break;
case 3:
itemID = R.id.fragment_4;
Log.d("HL", "4");
break;
case 4:
itemID = R.id.fragment_5;
Log.d("HL", "5");
break;
default:
break;
}
//TODO 当Fragment滑动改变时,底部的Tab也跟着改变
mBottomNavigationView.setSelectedItemId(itemID);
}
};
NavigationBarView.OnItemSelectedListener onItemSelectedListener = new NavigationBarView.OnItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
// 点击Tab, 切换对应的 Fragment
switch (item.getItemId()) {
case R.id.fragment_1:
//TODO 当点击 Tab 时,ViewPager 也切换到对应的 Fragment
mViewPager.setCurrentItem(0, true);
return true;
case R.id.fragment_2:
mViewPager.setCurrentItem(1, true);
return true;
case R.id.fragment_3:
mViewPager.setCurrentItem(2, true);
return true;
case R.id.fragment_4:
mViewPager.setCurrentItem(3, true);
return true;
case R.id.fragment_5:
mViewPager.setCurrentItem(4, true);
return true;
}
return false;
}
};
/**
* 初始化数据
*/
private List<Fragment> initData(){
mData = new ArrayList<>();
for (int i = 0; i < 5; i++) {
mData.add(MyFragment.newInstance(i));
}
return mData;
}
}
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
我正在尝试将全局导航菜单项添加到我的ActiveAdmin安装(在“仪表板”导航按钮旁边)。ActiveAdmin说这在他们的网站上是可能的,但他们没有任何关于如何实现它的文档。有谁知道如何做到这一点?编辑:抱歉,我应该更清楚。我想添加一个指向由任意文本/链接对组成的全局导航的链接。IE,如果我想添加一个链接到http://google.com在事件管理员的全局导航中使用文本“Google”,我将如何实现? 最佳答案 ActiveAdmin.register_page"Google"domenu:priority=>1,:label
伴随农业机械化和智能化的发展,越来越多的人开始使用农机自动驾驶系统助力耕作,千耘农机导航的“星地一体”能力可有效解决信号受限的问题,实现作业提效。究竟什么是“星地一体”,又是如何解决智能化农机作业的痛点的?下面为大家揭秘。农机效率通常受限于通信网络目前虽然我国通讯网络的人口覆盖率达到99%,但地面移动通讯网络覆盖率仍小于国土面积的40%,而很多农田所在区域恰是山区、戈壁滩等偏远地区。两省交界地也会出现通信信号不稳定的状况;而国内大部分农机自动驾驶系统非常依赖通信网络,当通信网络弱的时候会出现系统掉线的现象,必须得携带小基站才能正常使用,极为繁琐。Q:什么是千耘农机导航“星地一体”能力?A:是星
我有一个Rails应用程序。还有一个javascript(javascript1.js)文件必须包含在每个View的最底部。我把它放在/assets/javascripts文件夹中。Application.js包含以下代码//=requirejquery//=requirejquery_ujs//=someotherfiles//=require_directory.即使Application.js中不包含javascript1.js,它也会自动包含,不是吗?那么我怎样才能做我想做的事呢? 最佳答案 单独定义、包含和执行您的java
运行有问题或需要源码请点赞关注收藏后评论区留言一、利用ContentResolver读写联系人在实际开发中,普通App很少会开放数据接口给其他应用访问。内容组件能够派上用场的情况往往是App想要访问系统应用的通讯数据,比如查看联系人,短信,通话记录等等,以及对这些通讯数据及逆行增删改查。首先要给AndroidMaifest.xml中添加响应的权限配置 下面是往手机通讯录添加联系人信息的例子效果如下分成三个步骤先查出联系人的基本信息,然后查询联系人号码,再查询联系人邮箱代码 ContactAddActivity类packagecom.example.chapter07;importandroid
1.前言 在10.0的系统rom定制化开发中,在系统中有多个launcher的时候,会在开机进入launcher的时候弹窗launcher列表,让用户选择进入哪个launcher,这样显得特别的不方便所以产品开发中,要求用RoleManager的相关api来设置默认Launcher,但是在设置完默认Launcher以后,在安装一款Launcher的时候,默认Launcher就会失效,在系统设置的默认应用中Launcher选项就为空,点击home键的时候会弹出默认Launcher列表,让选择进入哪个默认Launcher.所以需要从安装Launcher的流程来分析相关的设置。来解决问题设置默认La
在railsadmin中,您可以像这样为模型及其子项定义导航标签:#inrails_admin.rbconfig.modelOrderdonavigation_label'Ordersrelated'endconfig.modelOrderProductsdoparentOrderend有没有办法在不创建模型的情况下向导航菜单添加标签(即仅用于分组)? 最佳答案 根据wiki,您可以像这样将静态链接附加到导航:RailsAdmin.configdo|config|config.navigation_static_links={'Go
Ruby2.3.0引入了安全导航语法,它通过引入一个新的运算符来简化链式方法调用的nil处理,该运算符仅在先前语句的值不是nil。这是一个已经存在于C#、Groovy和Swift中的特性。例如inGroovy,语法是foo?.bar这基本上意味着结果值是foo.bar除非foo是null,在这种情况下返回值也是null因此不会抛出异常。还有C#(称为空条件运算符)和Swift(称为可选链接表达式)使用此表示法。所以语法在其他语言中似乎是相当标准的。现在,为什么在Ruby中语法是foo&.bar代替? 最佳答案 此答案基于thedis
我只是习惯了Middleman和一般的ruby。生成具有事件状态的导航的最佳方式是什么? 最佳答案 在当前版本的MM(2.x,尽管3.0接近)中,您可以通过向config.rb添加以下内容并在您的导航文件中进行一些调整来实现。这是aworkingversion以防我遗漏一些关键位:首先创建一个辅助函数:helpersdodefnav_active(page)@page_id==page?{:class=>"Active"}:{}endend然后,在navbarincludefile(在本例中它是一个haml文件)您可以使用nav_a