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

news2024/11/24 15:48:52

文章目录

  • 1. Fragment
    • 1.1 Fragment的特性
    • 1.2 Fragment的基本使用步骤
    • 1.3 动态添加Fragment基本步骤
    • 1.4 Fragment与Activity的通信
        • 原生方案:Bundle类
        • 深入方案:java类与类通信的方案:接口
          • Activity从Fragment获取消息
          • Fragment从Activity获取消息
        • 其他方案:enventBus、LiveData
    • 1.5 Fragment的生命周期
        • 操作Fragment时生命周期的运行情况
        • 按下主屏键
        • 重新打开界面
        • 按后退键
    • 1.6 Fragment与ViewPager2联合使用
        • ViewPager2简单使用的步骤
        • ViewPager2 + Fragment形成翻页效果
        • ViewPager2 + Fragment模拟微信翻页界面
          • 程序中所用到的图片链接如下
          • 颜色资源
          • drawable资源
          • fragment布局设计(可后续修改)
          • 底边栏布局设计(可后续修改)
          • 主界面布局文件设计——需要使用include引用前面的底边栏xml文件
          • Fragment.java文件初始化fragment.xml布局文件
          • 适配器匹配ViewPager和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 -->
    <TextView
        android:id="@+id/fragment1_textview"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:text="@string/hello_blank_fragment" />
    <Button
        android: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;

    // 生命周期函数 创建时调用
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }
    // 渲染布局文件函数 创建时调用 有返回值
    @Override
    public 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() {
            @Override
            public 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、宽和高-->
    <fragment
        android:name="com.example.byfragmenttestmyself.BlankFragment1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:id="@+id/main_fragment1" />
    <fragment
        android: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(不携带背景)-->
    <Button
        android:background="#00ff00"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn_1"
        android:text="@string/change"/>
    <Button
        android:background="#00ff00"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn_2"
        android:text="@string/replace"/>
    <FrameLayout
        android: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 {
    @Override
    protected 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);
        }
    }
    @Override
    public 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());
        }
    }
    // 动态切换fragment
    private void replaceFragment(Fragment fragment) {
        // 获取默认的fragment管理类,用于管理fragment
        FragmentManager fragmentManager = getSupportFragmentManager();
        // 获取一个transaction,完成fragment的替换动作
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        // 替换fragment
        transaction.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() {
        @Override
        public 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() {
            @Override
            public void sendMsgToActivity(String msg) {
                Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();
            }

            @Override
            public 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() {
    @Override
    public void sendMsgToActivity(String msg) {
        Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();
    }

    @Override
    public 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.ViewPager2
        android: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">

    <TextView
        android: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 {

    @Override
    protected 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的适配界面
    @Override
    public 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~#FFFFFF
        holder.mContainer.setBackgroundResource(colors.get(position));
    }

    // 返回页面的数量
    @Override
    public 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.ViewPager2
        android: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;
    @Override
    protected 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 -->
    <TextView
        android: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;
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            // 通过获取Bundle的方式获取参数的值
            mTextString = getArguments().getString(ARG_TEXT);
        }
    }
    @Override
    public 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
    @Override
    public Fragment createFragment(int position) {
        return fragments.get(position);
    }

    @Override
    public 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 -->
    <TextView
        android: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">

    <LinearLayout
        android: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">
        <ImageView
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:id="@+id/tb_image_weixin"
            android:background="@drawable/tab_weixin"/>
        <TextView
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:id="@+id/text_weixin"
            android:gravity="center"
            android:text="微信"
            android:textColor="@color/green"/>
    </LinearLayout>

    <LinearLayout
        android: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">
        <ImageView
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:id="@+id/tb_image_contact"
            android:background="@drawable/tab_contact"/>
        <TextView
            android: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>

    <LinearLayout
        android: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">
        <ImageView
            android:layout_marginTop="4dp"
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:id="@+id/tb_image_search"
            android:background="@drawable/tab_search"/>
        <TextView
            android: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>

    <LinearLayout
        android: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">
        <ImageView
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:id="@+id/tb_image_me"
            android:background="@drawable/tab_me"/>
        <TextView
            android: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.ViewPager2
        android: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;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            // 通过获取Bundle的方式获取参数的值
            mTextString = getArguments().getString(ARG_TEXT);
        }
    }

    @Override
    public 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
    @Override
    public Fragment createFragment(int position) {
        return fragments.get(position);
    }

    @Override
    public 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;
    @Override
    protected 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;
        }
    }

    @Override
    public 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.coloradmin.cn/o/1796149.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

德国80%的统计学教授都会答错的6个与P值有关的问题!

小编阅读了一篇发表于2002年关于P值的一项问卷调查研究 [1]&#xff0c;作者在6所德国大学中邀请了3组不同的受试者&#xff0c;分别为: 心理学专业的学生(n 44)&#xff1b;主要从事科学研究但不进行统计相关教学的教授和讲师(n 39)&#xff1b;进行统计相关教学的教授和讲师…

05-控制流(分支结构)

05-控制流(分支结构) 一、二路分支 程序中某一段代码需要满足一定的条件才会被执行。 if 语句&#xff1a;用于表达一种条件&#xff0c;如果条件满足则执行某个代码块。if-else 语句&#xff1a;用于表达一种条件&#xff0c;如果条件满足则执行某个代码块&#xff0c;否则…

微信小程序bindgetphonenumber获取手机号阻止冒泡触发

问题&#xff1a;点击手机号弹出微信的手机号验证组件&#xff0c;这是可以的。但是我点击车牌号&#xff0c;也弹出来了&#xff0c;这就郁闷了。 以下是解决方法 点击手机号时&#xff0c;弹出选择手机号 解决&#xff1a; <view style"display: flex;justify-conte…

Facebook开户|Facebook广告设计与测试优化

早上好家人们~今天Zoey给大家伙带来的是Facebook广告设计与测试优化&#xff0c;需要的家人们看过来啦&#xff01; 一、避免复杂用图和过多的文字 根据Facebook的数据显示&#xff0c;用户平均浏览一个贴文的时间在手机上仅花1.7秒、在电脑上则为2.5秒。因此&#xff0c;广告…

Java1.8 vue版家政服务系统成品源码 家政管家系统源码 家政月嫂系统源码 家政保洁系统源码 在线派单,师傅入驻全套商业源码

Java1.8 vue版家政服务系统成品源码 家政管家系统源码 家政月嫂系统源码 家政保洁系统源码 在线派单&#xff0c;师傅入驻全套商业源码 一、系统定义 家政上门服务系统是一种利用互联网技术&#xff0c;将家政服务需求与专业的家政服务人员进行高效匹配的平台。它允许用户通过…

LeetCode-704. 二分查找【数组 二分查找】

LeetCode-704. 二分查找【数组 二分查找】 题目描述&#xff1a;解题思路一&#xff1a;注意开区间和闭区间背诵版&#xff1a;解题思路三&#xff1a; 题目描述&#xff1a; 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xf…

Partially Spoofed Audio Detection论文介绍(ICASSP 2024)

An Efficient Temporary Deepfake Location Approach Based Embeddings for Partially Spoofed Audio Detection 论文翻译名&#xff1a;一种基于部分欺骗音频检测的基于临时深度伪造位置方法的高效嵌入 摘要&#xff1a; 部分伪造音频检测是一项具有挑战性的任务&#xff0…

水电表自动抄表系统

1.简述 水电表自动抄表系统是一种现代化智能化管理系统&#xff0c;它利用先进的物联网&#xff0c;完成了远程控制、即时、零接触的水电表读值收集&#xff0c;大大提升了公共事业服务项目的效率和准确性。该系统不仅减少了人工抄表工作量&#xff0c;还避免了人为失误&#…

【NOIP2020普及组复赛】题3:方格取数

题3&#xff1a;方格取数 【题目描述】 设有 nm 的方格图&#xff0c;每个方格中都有一个整数。现有一只小熊&#xff0c;想从图的左上角走到右下角&#xff0c;每一步只能向上、向下或向右走一格&#xff0c;并且不能重复经过已经走过的方格&#xff0c;也不能走出边界。小熊…

神经网络搭建(1)----nn.Sequential

神经网络模型构建 采用CIFAR10中的数据&#xff0c;并对其进行简单的分类。以下图为例 输入&#xff1a;3通道&#xff0c;3232 ( 经过一个55的卷积) → 变成32通道&#xff0c;3232的图像 (经过22的最大池化) → 变成32通道&#xff0c;1616的图像 ( 经过一个55的卷积) → 变…

电商售后常见的客服快捷语

在电商行业&#xff0c;优质的客户服务体验是留住顾客、建立品牌信誉的关键。面对多样化的售后请求&#xff0c;如何高效、准确地回应顾客&#xff0c;成为每个客服团队必须面对的挑战。今天&#xff0c;我给大家分享一些电商售后常见的客服快捷语&#xff0c;帮助客服人员提高…

AIGC 011-SAM第一个图像分割大模型-分割一切!

AIGC 011-SAM第一个图像分割大模型-分割一切&#xff01; 文章目录 0 论文工作1论文方法2 效果 0 论文工作 这篇论文介绍了 Segment Anything (SA) 项目&#xff0c;这是一个全新的图像分割任务、模型和数据集。SA 项目是一个具有里程碑意义的工作&#xff0c;它为图像分割领域…

网络安全:https劫持

文章目录 参考https原理https窃听手段SSL/TLS降级原理难点缺点 SSL剥离原理发展缺点前端劫持 MITM攻击透明代理劫持 参考 https原理 SNI 浏览器校验SSL证书 https降级 https握手抓包解析 lets encrypt申请证书 https原理 步骤如下&#xff1a; 客户端向服务器发送https请求。…

Java大文件上传、分片上传、多文件上传、断点续传、上传文件minio、分片上传minio等解决方案

一、上传说明 文件上传花样百出&#xff0c;根据不同场景使用不同方案进行实现尤为必要。通常开发过程中&#xff0c;文件较小&#xff0c;直接将文件转化为字节流上传到服务器&#xff0c;但是文件较大时&#xff0c;用普通的方法上传&#xff0c;显然效果不是很好&#xff0c…

docker 拉取不到镜像的问题:拉取超时

error pulling image configuration: download failed after attempts6: dial tcp 31.13.94.10:443: i/o timeout 首先设置国内的镜像源&#xff1a;复制下面直接执行 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF{"registry-mirrors"…

k8s学习--Secret详细解释与应用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Secret什么是Secret?Secret四种类型及其特点Secret应用案例&#xff08;1&#xff09;将明文密码进行base64编码&#xff08;2&#xff09;编写创建secret的YAML文…

【人工智能003】图像识别算法模型常见术语简单总结(已更新)

1.熟悉、梳理、总结数据分析实战中的AI图像识别等实战研发知识体系&#xff0c;这块领域很大&#xff0c;需要耗费很多精力&#xff0c;逐步总结、更新到位&#xff0c;&#xff0c;&#xff0c; 2.欢迎点赞、关注、批评、指正&#xff0c;互三走起来&#xff0c;小手动起来&am…

心理咨询系统|心理咨询系统成品开发功能

心理咨询系统开发后端设计是一个复杂且精细的过程&#xff0c;涉及多个关键领域的专业知识和技术。本文将详细探讨心理咨询系统开发后端设计的各个方面&#xff0c;包括系统架构、数据库设计、接口开发、安全性保障以及性能优化等。 首先&#xff0c;我们来谈谈系统架构。在心理…

贝锐蒲公英异地组网:降低建筑工地远程视频监控成本、简化运维

中联建设集团股份有限公司是一家建筑行业的施工单位&#xff0c;专注于建筑施工&#xff0c;业务涉及市政公用工程施工总承包、水利水电工程施工总承包、公路工程施工总承包、城市园林绿化专业承包等&#xff0c;在全国各地开展有多个建筑项目&#xff0c;并且项目时间周期可能…

mac M1下安装PySide2

在M1下装不了PySide2, 是因为PySide2没有arm架构的包 1 先在M1上装qt5 安装qt主要是为了能用里面的Desinger, uic, rcc brew install qt5 我装完的路径在/opt/homebrew/opt/qt5 其中Designer就是用来设计界面的 rcc用resource compiler, 编绎rc资源文件的, 生成对应的py文件…