Android精通值Fragment的使用 —— 不含底层逻辑(五)

1. Fragment

使用Fragment的目标:根据列表动态显示内容,更简洁显示界面、查找界面

eg. 使用新闻列表动态显示新闻

1.1 Fragment的特性

  1. 具备生命周期 —— 可以动态地移除一些Fragment
  2. 必须委托在Activity中使用
  3. 可以在Activity中进行复用

1.2 Fragment的基本使用步骤

  1. 在包中添加一个空的Fragment板块(生成一个java文件和一个xml文件)
  2. 设置(Fragment)xml文件布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:orientation="vertical"tools:context=".BlankFragment1"><!-- TODO: Update blank fragment layout --><TextViewandroid:id="@+id/fragment1_textview"android:layout_width="match_parent"android:layout_height="40dp"android:text="@string/hello_blank_fragment" /><Buttonandroid:id="@+id/fragment1_button"android:layout_width="match_parent"android:text="how are you"android:layout_height="40dp"/>
</FrameLayout>
  1. 在java文件中设计相关逻辑处理
package com.example.byfragmenttestmyself;import android.graphics.Color;
import android.os.Bundle;import androidx.fragment.app.Fragment;import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;// 这个类继承自(拓展于) Fragment
public class BlankFragment1 extends Fragment {private View root = null;private TextView fragment1_textview = null;private Button fragment1_button = null;// 生命周期函数 创建时调用@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}// 渲染布局文件函数 创建时调用 有返回值@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// 基本渲染判断if(root == null){root = inflater.inflate(R.layout.fragment_blank1,container,false);}// 获取xml 控件资源fragment1_textview = root.findViewById(R.id.fragment1_textview);fragment1_button = root.findViewById(R.id.fragment1_button);fragment1_button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 使用Toast显示点击后显示的内容Toast.makeText(getContext(),"I am fine,and you?",Toast.LENGTH_SHORT).show();}});return root;}
}
  1. 在需要添加Fragment的Activity文件中添加对应名字的fragment标签(必须添加name和id属性)
<?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"><!--fragment组件必须要有的元素有name、id、宽和高--><fragmentandroid:name="com.example.byfragmenttestmyself.BlankFragment1"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_weight="1"android:id="@+id/main_fragment1" /><fragmentandroid:name="com.example.byfragmenttestmyself.BlankFragment2"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_weight="1"android:id="@+id/main_fragment2" />
</LinearLayout>

1.3 动态添加Fragment基本步骤

  1. 在主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=".MainActivity"><!--这里可以使用android.widget.Button(不携带背景)--><Buttonandroid:background="#00ff00"android:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn_1"android:text="@string/change"/><Buttonandroid:background="#00ff00"android:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn_2"android:text="@string/replace"/><FrameLayoutandroid:background="#3FE8CE"android:id="@+id/fragment_layout"android:layout_width="match_parent"android:layout_height="match_parent"></FrameLayout>
</LinearLayout>
  1. 创建两个Fragment

    • 我使用的是一个BlackFragment和一个ListFragmen
  2. 在MainActivity中设置相关的逻辑

    • 创建一个待处理的fragment
    • 获取FragmentManager,一般都是通过getSupportFragmentManager()
    • 开启一个事物transaction,一般调用FragmentManager的beginTransaction()
    • 使用transaction进行fagment的替换
    • 提交事物
package com.example.fragment2;import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;import android.os.Bundle;
import android.view.View;
import android.widget.Button;public class MainActivity extends AppCompatActivity implements View.OnClickListener {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);{// 可以将这段代码写进一个initView()函数中Button button1 = findViewById(R.id.btn_1);Button button2 = findViewById(R.id.btn_2);button1.setOnClickListener(this);button2.setOnClickListener(this);}}@Overridepublic void onClick(View v) {if(v.getId() == R.id.btn_1){replaceFragment(new BlankFragment1());}else if(v.getId() == R.id.btn_2){replaceFragment(new ItemFragment());}}// 动态切换fragmentprivate void replaceFragment(Fragment fragment) {// 获取默认的fragment管理类,用于管理fragmentFragmentManager fragmentManager = getSupportFragmentManager();// 获取一个transaction,完成fragment的替换动作FragmentTransaction transaction = fragmentManager.beginTransaction();// 替换fragmenttransaction.replace(R.id.fragment_layout,fragment);// 设置一个fragment栈来存储所有添加的fragment// 在栈内存在fragment的时候,响应由fragment栈来承担,如果栈内没有了fragment,响应由Activity承担transaction.addToBackStack(null);// 以上都是事物的处理过程,最后需要提交事物transaction.commit();}
}

1.4 Fragment与Activity的通信

原生方案:Bundle类

在上面代码(1.3动态添加Fragment)进行修改

过程

  1. 修改MainActivity.java文件
@Override
public void onClick(View v) {if(v.getId() == R.id.btn_1){// 新建一个Bundle对象Bundle bundle = new Bundle();// 向Bundle中传入string数据bundle.putString("message","我喜欢小学课堂");// 利用bundle将数据传入Fragment中BlankFragment1 bf = new BlankFragment1();bf.setArguments(bundle);replaceFragment(bf);}else if(v.getId() == R.id.btn_2){replaceFragment(new ItemFragment());}
}
  1. 修改BlackFragment1文件接收传过来的Bundle数据
@Override
public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 在Fragment中的任意地方接收相应数据Bundle bundle = this.getArguments();// 创建一个String作为日志打印输出String string = null;if (bundle != null) {bundle.getString("message");string = "我好喜欢学习呀。";Log.d(TAG,"onCreate:" + string);}if (getArguments() != null) {mParam1 = getArguments().getString(ARG_PARAM1);mParam2 = getArguments().getString(ARG_PARAM2);}
}

效果

可以在点击Button的时候,在日志中输出一段文字。说明了这段代码实现了数据在Activity和Fragment之间的传递。

深入方案:java类与类通信的方案:接口
Activity从Fragment获取消息
  1. 定义一个接口
package com.example.fragment2;public interface IFragmentCallback {public void sendMsgToActivity(String msg);public String getMsgFromActivity(String msg);
}
  1. 在Fragment中写一个接口的实现
private View rootView = null;// 为MainActivity提供接口,用于创建对象
private IFragmentCallback fragmentCallback;
public void setFragmentCallback(IFragmentCallback callback){fragmentCallback = callback;
}@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragment// 防止被解析多次,定义成一个全局变量if(rootView == null){rootView = inflater.inflate(R.layout.fragment_blank1,container,false);}Button btn = rootView.findViewById(R.id.btn_3);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 调用方法传递数值fragmentCallback.sendMsgToActivity("hello,I am from Fragment");}});return rootView;
}
  1. 在MainActivity中实现前面定义的接口(在点击事件处理中),等待后面Fragment中的调用
public void onClick(View v) {if(v.getId() == R.id.btn_1){// 新建一个Bundle对象Bundle bundle = new Bundle();// 向Bundle中传入string数据bundle.putString("message","我喜欢小学课堂");// 利用bundle将数据传入Fragment中BlankFragment1 bf = new BlankFragment1();bf.setFragmentCallback(new IFragmentCallback() {@Overridepublic void sendMsgToActivity(String msg) {Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();}@Overridepublic String getMsgFromActivity(String msg) {return null;}});bf.setArguments(bundle);replaceFragment(bf);}else if(v.getId() == R.id.btn_2){replaceFragment(new ItemFragment());}
}
Fragment从Activity获取消息

从上面代码修改:

  1. 修改Fragment点击事件
@Override
public void onClick(View v) {
//    fragmentCallback.sendMsgToActivity("hello,I am from Fragment");String msg = fragmentCallback.getMsgFromActivity("null");Toast.makeText(getContext(),msg,Toast.LENGTH_SHORT).show();
}
  1. 修改MainActivity的接口方法重写
bf.setFragmentCallback(new IFragmentCallback() {@Overridepublic void sendMsgToActivity(String msg) {Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();}@Overridepublic String getMsgFromActivity(String msg) {return "hello,I am from Activity";}
});

比较巧妙的是:函数的返回值为数据的发送和接受实现了不同的逻辑处理,体现了代码的高内聚

其他方案:enventBus、LiveData

使用的设计模式:发布订阅模式、观察者模式

Fragment可以观察Activity,Fragment可以选择地使用。

1.5 Fragment的生命周期

上面有一个onAttach方法没有被官方文档显示(我也不知道为啥)于是我在文心一言上问了一下,得到了一下的结果:

  1. onAttach(Activity activity): 这是较旧的方法,但在较新的 Android 版本中仍然可用。当您使用这种方法时,您需要确保在代码中适当地处理它,因为 Activity 参数可能是 null(尽管这在正常情况下不应该发生)。
  2. onAttach(Context context): 这是较新的方法,它允许您接收一个 Context 对象,该对象可以是 Activity 或其他类型的上下文(尽管在 Fragment 的情况下,它通常是一个 Activity)。这种方法提供了更灵活的方式来处理与宿主 Activity 的关联,并且不需要担心 Activity 参数为 null 的情况。

总而言之,onAttach的作用就是绑定与之对应的父类。

注意:

当我们以后在Fragment中获取Activity,返回值为空的时候就是因为我们没有将所有的周期函数写在Activity

详情请点击链接

操作Fragment时生命周期的运行情况

打开界面

onCreate() -> onCreateView() -> onActivityCreated() -> onStart() -> onResume()
按下主屏键
onPause() -> onStop()
重新打开界面
onStart() -> onResume()
按后退键
onPause() -> onStop() -> onDestroyView() -> onDestroy() -> onDetach()

1.6 Fragment与ViewPager2联合使用

优势:减少用户的操作;

ViewPager2与ViewPager2的优势:

ViewPager1是以GridLayout作为底层来生成的;ViewPager2是以ListLayout为底层逻辑生成的。ViewPager2具有懒加载的特性

ViewPager2简单使用的步骤
  1. 定义一个ViewPager2

<!--activity_main.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=".MainActivity"><androidx.viewpager2.widget.ViewPager2android:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/viewPager"android:background="@color/blue"></androidx.viewpager2.widget.ViewPager2></LinearLayout>
<!--item_pager.xml-->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:id="@+id/container__"android:layout_height="match_parent"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/tvTitle"android:layout_centerInParent="true"android:textColor="#ff4532"android:textSize="32sp"android:text="hello"/>
</RelativeLayout>
<!--color.xml-->
<?xml version="1.0" encoding="utf-8"?>
<resources><color name="black">#FF000000</color><color name="white">#FFFFFFFF</color><color name="blue">#0000FF</color><color name="red">#FF0000</color><color name="yellow">#FFFF00</color>
</resources>
// MainActivity.java
package com.example.viewpager;import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;import android.os.Bundle;
import android.view.View;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ViewPager2 viewPager = findViewById(R.id.viewPager);ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter();viewPager.setAdapter(viewPagerAdapter);}
}
  1. 为ViewPager2构建Adapter
// ViewPagerAdapter.java
package com.example.viewpager;import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;import java.util.ArrayList;
import java.util.List;// 下面的拓展RecyclerView.Adapter可以通过前面的调用自动生成
public class ViewPagerAdapter extends RecyclerView.Adapter<ViewPagerAdapter.ViewPagerViewHolder> {private List<String> title = new ArrayList<>();private List<Integer> colors = new ArrayList<>();// 根据下面的页面数量适配相应数量的数据public ViewPagerAdapter(){title.add("hello");title.add("520");title.add("我爱你");title.add("6.1快乐");colors.add(R.color.yellow);colors.add(R.color.blue);colors.add(R.color.red);colors.add(R.color.white);}@NonNull// ViewPager的适配界面@Overridepublic ViewPagerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {return new ViewPagerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_pager,parent,false));}// 对列表中的数据进行绑定@Override/*position 显示当前滑动的是哪一个item*/public void onBindViewHolder(@NonNull ViewPagerViewHolder holder, int position) {holder.mTextView.setText(title.get(position));// 上面做链表的时候传入的是一个资源的id,所以这里的方法需要用setBackgroundResource()// 如果需要设置的是一个color,可以添加#000000~#FFFFFFholder.mContainer.setBackgroundResource(colors.get(position));}// 返回页面的数量@Overridepublic int getItemCount() {return 4;}// 定义一个内部类专门用于RecyclerView的封装class ViewPagerViewHolder extends RecyclerView.ViewHolder{TextView mTextView = null;RelativeLayout mContainer = null;public ViewPagerViewHolder(@NonNull View itemView) {super(itemView);// 参数 View 就是item_pager.xml布局文件mContainer = itemView.findViewById(R.id.container__);mTextView = itemView.findViewById(R.id.tvTitle);}}
}
ViewPager2 + Fragment形成翻页效果

activity作为宿主,Fragment附庸在宿主上显示

<!--activity_main.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:orientation="vertical"android:layout_height="match_parent"tools:context=".MainActivity">
<!--    高度设置为0dp可以实现适应性填充--><androidx.viewpager2.widget.ViewPager2android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:id="@+id/viewpager"/>
</LinearLayout>
// MainActivity.java
package com.example.wechatpage;import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;import android.os.Bundle;import java.util.ArrayList;public class MainActivity extends AppCompatActivity {ViewPager2 viewPager = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initPager();}private void initPager() {viewPager = findViewById(R.id.viewpager);ArrayList<Fragment> fragments = new ArrayList<>();fragments.add(BlankFragment.newInstance("微信聊天"));fragments.add(BlankFragment.newInstance("通讯录"));fragments.add(BlankFragment.newInstance("发现"));fragments.add(BlankFragment.newInstance("我"));MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(),// 第二个参数使用了jetpack控件 现在的版本主要使用 vm 和 mv 模式中调用getLifecycle(),fragments);viewPager.setAdapter(pagerAdapter);}
}
<!--fragment_blank.xml-->
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:orientation="vertical"tools:context=".BlankFragment"><!-- TODO: Update blank fragment layout --><TextViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:textSize="36sp"android:id="@+id/text_word"android:text="@string/hello_blank_fragment" />
</FrameLayout>
// BlackFragment.java
package com.example.wechatpage;import android.os.Bundle;import androidx.fragment.app.Fragment;import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;public class BlankFragment extends Fragment {View rootView = null;private static final String ARG_TEXT = "param1";private String mTextString;public BlankFragment() {// Required empty public constructor}// 将参数传入Bundle对象public static BlankFragment newInstance(String param1) {BlankFragment fragment = new BlankFragment();Bundle args = new Bundle();args.putString(ARG_TEXT, param1);fragment.setArguments(args);return fragment;}@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (getArguments() != null) {// 通过获取Bundle的方式获取参数的值mTextString = getArguments().getString(ARG_TEXT);}}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// 防止重复解析xml造成的资源浪费if(rootView == null){rootView = inflater.inflate(R.layout.fragment_blank, container, false);}initView();return rootView;}private void initView() {TextView textView = rootView.findViewById(R.id.text_word);textView.setText(mTextString);}
}
// MyFragmentPagerAdapter.java
package com.example.wechatpage;import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;import java.util.ArrayList;
import java.util.List;public class MyFragmentPagerAdapter extends FragmentStateAdapter {List<Fragment> fragments = new ArrayList<>();public MyFragmentPagerAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle,List<Fragment> fragmentList) {super(fragmentManager, lifecycle);fragments = fragmentList;}@NonNull@Overridepublic Fragment createFragment(int position) {return fragments.get(position);}@Overridepublic int getItemCount() {return fragments.size();}
}

实现效果:翻页中间屏幕显示相应文字

ViewPager2 + Fragment模拟微信翻页界面
程序中所用到的图片链接如下

https://img.picui.cn/free/2024/06/02/665bd7676b127.png
https://img.picui.cn/free/2024/06/02/665bd7677abd5.png
https://img.picui.cn/free/2024/06/02/665bd7679745d.png
https://img.picui.cn/free/2024/06/02/665bd7676583f.png
https://img.picui.cn/free/2024/06/02/665bd76784bce.png
https://img.picui.cn/free/2024/06/02/665bd768c1583.png
https://img.picui.cn/free/2024/06/02/665bd7693a984.png
https://img.picui.cn/free/2024/06/02/665bd76a323ce.png

颜色资源
<?xml version="1.0" encoding="utf-8"?>
<resources><color name="black">#FF000000</color><color name="white">#FFFFFFFF</color><color name="blue">#5656FF</color><color name="green">#00FF00</color>
</resources>
drawable资源
<!--tab_contact.xml-->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@drawable/contacts_pressed" android:state_selected="true"/><item android:drawable="@drawable/contacts_normal"/>
</selector>
<!--tab_me.xml-->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@drawable/me_pressed" android:state_selected="true"/><item android:drawable="@drawable/me_normal"/>
</selector>
<!--tab_search.xml-->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@drawable/search_pressed" android:state_selected="true"/><item android:drawable="@drawable/search_normal"/>
</selector>
<!--tab_weixin.xml-->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@drawable/weixin_pressed" android:state_selected="true"/><item android:drawable="@drawable/weixin_normal"/>
</selector>
fragment布局设计(可后续修改)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:orientation="vertical"tools:context=".BlankFragment"><!-- TODO: Update blank fragment layout --><TextViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:textSize="36sp"android:id="@+id/text_word"android:text="@string/hello_blank_fragment" /></FrameLayout>
底边栏布局设计(可后续修改)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:orientation="horizontal"android:layout_height="55dp"android:background="@color/blue"><LinearLayoutandroid:gravity="center_horizontal"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:layout_gravity="center"android:orientation="vertical"android:id="@+id/tab_weixin"><ImageViewandroid:layout_width="32dp"android:layout_height="32dp"android:id="@+id/tb_image_weixin"android:background="@drawable/tab_weixin"/><TextViewandroid:layout_width="32dp"android:layout_height="32dp"android:id="@+id/text_weixin"android:gravity="center"android:text="微信"android:textColor="@color/green"/></LinearLayout><LinearLayoutandroid:gravity="center_horizontal"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:layout_gravity="center"android:orientation="vertical"android:id="@+id/tab_contact"><ImageViewandroid:layout_width="32dp"android:layout_height="32dp"android:id="@+id/tb_image_contact"android:background="@drawable/tab_contact"/><TextViewandroid:layout_marginTop="5dp"android:layout_width="32dp"android:layout_height="32dp"android:id="@+id/text_contact"android:gravity="center"android:text="通讯录"android:textColor="@color/green"/></LinearLayout><LinearLayoutandroid:gravity="center_horizontal"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:layout_gravity="center"android:orientation="vertical"android:id="@+id/tab_search"><ImageViewandroid:layout_marginTop="4dp"android:layout_width="25dp"android:layout_height="25dp"android:id="@+id/tb_image_search"android:background="@drawable/tab_search"/><TextViewandroid:layout_marginTop="3dp"android:layout_width="32dp"android:layout_height="32dp"android:id="@+id/text_search"android:gravity="center"android:text="发现"android:textColor="@color/green"/></LinearLayout><LinearLayoutandroid:gravity="center_horizontal"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:layout_gravity="center"android:orientation="vertical"android:id="@+id/tab_me"><ImageViewandroid:layout_width="32dp"android:layout_height="32dp"android:id="@+id/tb_image_me"android:background="@drawable/tab_me"/><TextViewandroid:layout_width="32dp"android:layout_height="32dp"android:id="@+id/text_me"android:gravity="center"android:text="我的"android:textColor="@color/green"/></LinearLayout>
</LinearLayout>
主界面布局文件设计——需要使用include引用前面的底边栏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:orientation="vertical"android:layout_height="match_parent"tools:context=".MainActivity"><!--    高度设置为0dp可以实现适应性填充--><androidx.viewpager2.widget.ViewPager2android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:id="@+id/viewpager"/>
<!--    通过include将其他的Activity加入到主Activity中--><include layout="@layout/bottom_layout"/>
</LinearLayout>
Fragment.java文件初始化fragment.xml布局文件
package com.example.wechatpage;import android.os.Bundle;import androidx.fragment.app.Fragment;import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;/*** A simple {@link Fragment} subclass.* Use the {@link BlankFragment#newInstance} factory method to* create an instance of this fragment.*/
public class BlankFragment extends Fragment {View rootView = null;private static final String ARG_TEXT = "param1";private String mTextString;public BlankFragment() {// Required empty public constructor}/*** Use this factory method to create a new instance of* this fragment using the provided parameters.** @param param1 Parameter 1.* @return A new instance of fragment BlankFragment.*/// TODO: Rename and change types and number of parameters// 将参数传入Bundle对象public static BlankFragment newInstance(String param1) {BlankFragment fragment = new BlankFragment();Bundle args = new Bundle();args.putString(ARG_TEXT, param1);fragment.setArguments(args);return fragment;}@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (getArguments() != null) {// 通过获取Bundle的方式获取参数的值mTextString = getArguments().getString(ARG_TEXT);}}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// 防止重复解析xml造成的资源浪费if(rootView == null){rootView = inflater.inflate(R.layout.fragment_blank, container, false);}initView();return rootView;}private void initView() {TextView textView = rootView.findViewById(R.id.text_word);textView.setText(mTextString);}
}
适配器匹配ViewPager和Fragment
package com.example.wechatpage;import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;import java.util.ArrayList;
import java.util.List;public class MyFragmentPagerAdapter extends FragmentStateAdapter {List<Fragment> fragments = new ArrayList<>();public MyFragmentPagerAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle,List<Fragment> fragmentList) {super(fragmentManager, lifecycle);fragments = fragmentList;}@NonNull@Overridepublic Fragment createFragment(int position) {return fragments.get(position);}@Overridepublic int getItemCount() {return fragments.size();}
}
主要逻辑处理(模板)
package com.example.wechatpage;import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;import java.util.ArrayList;public class MainActivity extends AppCompatActivity implements View.OnClickListener {ViewPager2 viewPager = null;private LinearLayout llChat = null;private LinearLayout llContacts = null;private LinearLayout llSearch = null;private LinearLayout llMe = null;private ImageView ivChat = null;private ImageView ivContacts = null;private ImageView ivSearch = null;private ImageView ivMe = null;private ImageView ivCurrent = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initPager();initTableView();}private void initTableView() {llChat = findViewById(R.id.tab_weixin);llContacts = findViewById(R.id.tab_contact);llSearch = findViewById(R.id.tab_search);llMe = findViewById(R.id.tab_me);ivChat = findViewById(R.id.tb_image_weixin);ivContacts = findViewById(R.id.tb_image_contact);ivSearch = findViewById(R.id.tb_image_search);ivMe = findViewById(R.id.tb_image_me);llChat.setOnClickListener(this);llContacts.setOnClickListener(this);llSearch.setOnClickListener(this);llMe.setOnClickListener(this);// 设置缓存按钮,用于后来复位ivChat.setSelected(true);ivCurrent = ivChat;}private void initPager() {viewPager = findViewById(R.id.viewpager);ArrayList<Fragment> fragments = new ArrayList<>();fragments.add(BlankFragment.newInstance("微信聊天"));fragments.add(BlankFragment.newInstance("通讯录"));fragments.add(BlankFragment.newInstance("发现"));fragments.add(BlankFragment.newInstance("我"));MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(),// 第二个参数使用了jetpack控件 现在的版本主要使用 vm 和 mv 模式中调用getLifecycle(),fragments);// 设置viewPager的内容viewPager.setAdapter(pagerAdapter);// 设置viewPager的滑动监听接口viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {@Override// 此方法可以为viewPager添加滚动动画效果public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {super.onPageScrolled(position, positionOffset, positionOffsetPixels);}@Override// 改变按钮的选择位置public void onPageSelected(int position) {super.onPageSelected(position);changeTable(position);}@Override//public void onPageScrollStateChanged(int state) {super.onPageScrollStateChanged(state);}});}private void changeTable(int position) {ivCurrent.setSelected(false);if(position == 0){ivChat.setSelected(true);ivCurrent = ivChat;}else if(position == 1){ivContacts.setSelected(true);ivCurrent = ivContacts;}else if(position == 2){ivSearch.setSelected(true);ivCurrent = ivSearch;}else if(position == 3){ivMe.setSelected(true);ivCurrent = ivMe;}}@Overridepublic void onClick(View v) {ivCurrent.setSelected(false);if(v.getId() == R.id.tab_weixin){ivChat.setSelected(true);ivCurrent = ivChat;viewPager.setCurrentItem(0);}else if(v.getId() == R.id.tab_contact){ivContacts.setSelected(true);ivCurrent = ivContacts;viewPager.setCurrentItem(1);}else if(v.getId() == R.id.tab_search){ivSearch.setSelected(true);ivCurrent = ivSearch;viewPager.setCurrentItem(2);}else if(v.getId() == R.id.tab_me){ivMe.setSelected(true);ivCurrent = ivMe;viewPager.setCurrentItem(3);}}
}

虽然很想写一下fragment和ViewPager的底层逻辑,但是时间有点不够了,要找资料,敲代码,写markdown……总而言之太麻烦了!,所以等有空的时候再补上吧画饼!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/339462.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

稍微学学react

文章开始前&#xff0c;先划划水~ 今日份开心&#xff1a; 今天看之前发布的按钮npm包下载量有162次&#xff0c;早知道好好做了 今日份不开心&#xff1a; 爬岗位看到一个整体都挺满意的岗位&#xff0c;公司位置和发展大方向都好喜欢&#xff01;&#xff01;&#xff01;…

Unity UGUI实现无限滚动列表

Demo链接: ​​​https://download.csdn.net/download/qq_41973169/89364284 在游戏开发中&#xff0c;列表视图是一个常见的UI组件。实现一个高效的列表视图尤其重要&#xff0c;尤其是在需要展示大量数据时。本文将介绍如何在Unity中实现一个高效的无限滚动列表&#xff0c;…

贪心算法拓展(反悔贪心)

相信大家对贪心算法已经见怪不怪了&#xff0c;但是一旦我们的决策条件会随着我们的步骤变化&#xff0c;我们该怎么办呢&#xff1f;有没有什么方法可以反悔呢&#xff1f; 今天就来讲可以后悔的贪心算法&#xff0c;反悔贪心。 https://www.luogu.com.cn/problem/CF865Dhttp…

100页2秒?我们为什么需要这样的文档解析速度

近期&#xff0c;TextIn通用文档解析完成最新一版产品迭代&#xff0c;将100页文档解析速度提升至最快2秒以内。 P50&#xff08;百页&#xff09; P90&#xff08;百页&#xff09; P95&#xff08;百页&#xff09; P99&#xff08;百页&#xff09; 平均&#xff08;单页…

C++:list模拟实现

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《C&#xff1a;list模拟实现》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 如果本篇文章对你有帮助&#xff0c;还请各位点点赞&#xff01;&#xf…

vue不同页面切换的方式(Vue动态组件)

v-if实现 <!--Calender.vue--> <template><a-calendar v-model:value"value" panelChange"onPanelChange" /></template> <script setup> import { ref } from vue; const value ref(); const onPanelChange (value, mod…

MySQL—函数—数值函数(基础)

一、引言 首先了解一下常见的数值函数哪些&#xff1f;并且直到它们的作用&#xff0c;并且演示这些函数的使用。 二、数值函数 常见的数值函数如下&#xff1a; 注意&#xff1a; 1、ceil(x)、floor(x) &#xff1a;向上、向下取整。 2、mod(x,y)&#xff1a;模运算&#x…

基于Springboot + vue实现的文化民俗网站

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

字节裁员!开启裁员新模式。。

最近&#xff0c;互联网圈不太平&#xff0c;裁员消息此起彼伏。而一向以“狼性文化”著称的字节跳动&#xff0c;却玩起了“低调裁员”&#xff0c;用一种近乎“温柔”的方式&#xff0c;慢慢挤掉“冗余”的员工。 “细水长流”&#xff1a;裁员新模式&#xff1f; 不同于以往…

2024年Google算法更新打击低质量(如AI生成)内容后,英文SEO优化人员该如何调整谷歌SEO优化策略?

3月5日&#xff0c;谷歌发布了2024年的首次算法更新。与以往更新不同&#xff0c;本次更新更加复杂&#xff0c;这次更新旨在提高搜索结果的质量和相关性&#xff0c;可能对外贸网站排名和流量产生显著影响。也将产生更大的网站数据波动。但在担心自己的网站数据受到影响之前&a…

【wiki知识库】04.SpringBoot后端实现电子书的增删改查以及前端界面的展示

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 一、&#x1f525;今日内容 二、&#x1f30f;前端页面的改造 2.1新增电子书管理页面 2.2新增路由规则 2.3修改the-header代码 三、&#x1f697;SpringBoot后端Ebook模块改造 3.1增加电子书增/改接口 3.1.…

数据挖掘 | 实验三 决策树分类算法

文章目录 一、目的与要求二、实验设备与环境、数据三、实验内容四、实验小结 一、目的与要求 1&#xff09;熟悉决策树的原理&#xff1b; 2&#xff09;熟练使用sklearn库中相关决策树分类算法、预测方法&#xff1b; 3&#xff09;熟悉pydotplus、 GraphViz等库中决策树模型…

盘点2024年还在活跃发版的开源私有网盘项目附源码链接

时不时的会有客户上门咨询&#xff0c;丰盘ECM是不是开源项目&#xff0c;源码在哪里可以下载&#xff1b;如果需要和内部其他系统做集成&#xff0c;购买商业版的话&#xff0c;能否提供源代码做二次开发呢&#xff0c;等等诸多问题。 这里做个统一回复&#xff0c;丰盘ECM产…

Docker安装极简版(三分钟搞定)

什么是Docker? Docker是一个开源的应用容器引擎&#xff0c;它允许开发者打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口。 化。容器是…

MLPerf storage基准测试

MLPerf 基准测试 什么是 MLPerf&#xff1f;MLPerf™ 基准测试由来自学术界、研究实验室和行业的 AI 领导者联盟 MLCommons 开发&#xff0c;旨在对硬件、软件和服务的训练和推理性能进行无偏评估。它们都在规定的条件下进行。为了保持在行业趋势的前沿&#xff0c;MLPerf 不断…

0基础认识C语言(理论知识)

为了给0基础一个舒服的学习路径&#xff0c;就有了这个专栏希望带大家一起进步。 话不多说&#xff0c;开始正题。 一、C语言的一段小历史 C语言的设计要追溯到20世纪60年代末和70年代初&#xff0c;在那个时代美国有这么一号人叫做丹尼斯.里奇&#xff0c;他和同事肯.汤普逊…

计算机网络学习实践:DHCP跨网段动态分配IP

计算机网络学习实践&#xff1a;DHCP跨网段动态分配IP 1.实验准备 实验环境&#xff1a;思科的模拟器 实验设备&#xff1a; 1个服务器&#xff0c;2个二层交换机&#xff08;不是三层的&#xff09;&#xff0c;4个PC机&#xff0c;1个路由器 三个网段 192.168.1.0 255.…

一些智能音箱类的软硬件方案

主要参考资料 Rabbit R1: https://www.rabbit.tech/rabbit-r1 mediatek-helio-p35: https://www.mediatek.com/products/smartphones-2/mediatek-helio-p35 NSdisplay: https://www.nsdisplay.com/ai-holobox-mini/ai-holobox-mini.html RK3566: https://www.rock-chips.com/a/…

Java学习Lambda表达式

Lambda表达式 有且只有一个未实现的方法叫做Lambda表达式&#xff0c;可以实现函数式编程 // 这个注解是用来检查你写的函数是否是函数式接口 FunctionalInterfaceinterface Myinterface {int sum(int a, int b);default String priteTitle(String name, int age, String sex)…

ASP+ACCESS酒店预定管理系统

【摘要】宏都大酒店管理信息系统中不能通过互联网方式进行客房预订&#xff0c;通过本次设计主要实现通过互联网方式进行客房预订。让客户足不出户坐在家里就能预订出自己想要的客房。主要功能有&#xff1a;酒店简介、客房简介、客房报价、客房预订信息提交&#xff0c;预订信…