当前位置: 首页 > news >正文

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……总而言之太麻烦了!,所以等有空的时候再补上吧画饼!

相关文章:

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

1. Fragment 使用Fragment的目标&#xff1a;根据列表动态显示内容&#xff0c;更简洁显示界面、查找界面 eg. 使用新闻列表动态显示新闻 1.1 Fragment的特性 具备生命周期 —— 可以动态地移除一些Fragment必须委托在Activity中使用可以在Activity中进行复用 1.2 Fragmen…...

apache大数据各组件部署搭建(超级详细)

apache大数据数仓各组件部署搭建 第一章 环境准备 1. 机器规划 准备3台服务器用于集群部署,系统建议CentOS7+,2核8G内存 172.19.195.228 hadoop101 172.19.195.229 hadoop102 172.19.195.230 hadoop103 [root@hadoop101 ~]# cat /etc/redhat-release CentOS Linux rele…...

Servlet搭建博客系统

现在我们可以使用Servlet来搭建一个动态(前后端可以交互)的博客系统了(使用Hexo只能实现一个纯静态的网页,即只能在后台自己上传博客)。有一种"多年媳妇熬成婆"的感觉。 一、准备工作 首先创建好项目,引入相关依赖。具体过程在"Servlet的创建"中介绍了。…...

NextJs 渲染篇 - 什么是CSR、SSR、SSG、ISR 和服务端/客户端组件

NextJs 渲染篇 - 什么是CSR、SSR、SSG、ISR 和服务端/客户端组件 前言一. 什么是CSR、SSR、SSG、ISR1.1 CSR 客户端渲染1.2 SSR 服务端渲染1.3 SSG 静态站点生成① 没有数据请求的页面② 页面内容需要请求数据③ 页面路径需要获取数据 1.4 ISR 增量静态再生1.5 四种渲染方式的对…...

Python 二叉数的实例化及遍历

首先创建一个这样的二叉树&#xff0c;作为我们今天的实例。实例代码在下方。 #创建1个树类型 class TreeNode:def __init__(self,val,leftNone,rightNone):self.valvalself.leftleftself.rightright #实例化类 node1TreeNode(5) node2TreeNode(6) node3TreeNode(7) node4Tre…...

计算 x 的二进制表示中 1 的个数

计算 x 的二进制表示中 1 的个数 代码如下&#xff1a; int func(int x){int countx 0;while (x>0){countx;x x & (x - 1);}return countx;} 完整代码&#xff1a; using System; using System.Collections.Generic; using System.ComponentModel; using System.Dat…...

基于Vue的前端瀑布流布局组件的设计与实现

摘要 随着前端技术的不断演进&#xff0c;复杂业务场景和多次迭代后的产品对组件化开发提出了更高的要求。传统的整块应用开发方式已无法满足快速迭代和高效维护的需求。因此&#xff0c;本文将介绍一款基于Vue的瀑布流布局组件&#xff0c;旨在通过组件化开发提升开发效率和降…...

WinSW使用说明

WinSW使用说明 Windows系统下部署多个java程序 场景&#xff1a; 多个java的jar程序&#xff0c;通常来说一个程序使用一个cmd窗口&#xff0c;通过java -jar xxx.jar 命令来运行。这样如果程序多了打开cmd窗口也就多了。 解决&#xff1a; 通过使用WinSW程序&#xff0c;把ja…...

SpringBoot 多模块 多环境 项目 单元测试

环境描述 假设项目中有以下三个yml文件&#xff1a; application.ymlapplication-dev.ymlapplication-prod.yml 假设项目各Module之间依赖关系如下&#xff1a; 其中&#xff0c;D依赖C&#xff0c;C依赖B&#xff0c;B依赖A&#xff0c;D对外提供最终的访问接口 现在要想采…...

网络安全法中的网络安全规定和措施

《中华人民共和国网络安全法》是中国首部全面规范网络空间安全管理的基础性法律&#xff0c;旨在加强网络安全&#xff0c;保障国家安全和社会公共利益&#xff0c;保护公民、法人和其他组织的合法权益&#xff0c;促进互联网的健康发展。以下是该法律中关于网络安全的一些核心…...

一、搭建 Vue3 Admin 项目:从无到有的精彩历程

在前端开发的领域中&#xff0c;Vue3 展现出了强大的魅力&#xff0c;而搭建一个功能丰富的 Vue3 Admin 项目更是充满挑战与乐趣。今天&#xff0c;我将和大家分享我搭建 Vue3 Admin 项目的详细过程&#xff0c;其中用到了一系列重要的依赖包。 首先 让我们开启这个旅程。在确…...

Qt | Qt 资源简介(rcc、qmake)

1、资源系统是一种独立于平台的机制,用于在应用程序的可执行文件中存储二进制文件(前面所讨论的数据都存储在外部设备中)。若应用程序始终需要一组特定的文件(比如图标),则非常有用。 2、资源系统基于 qmake,rcc(Qt 的资源编译器,用于把资源转换为 C++代码)和 QFile …...

对boot项目拆分成cloud项目的笔记

引言&#xff1a;这里我用的是新版本的技术栈 spring-boot-starter-parent >3.2.5 mybatis-spring-boot-starter >3.0.3 mybatis-plus-boot-starter >3.5.5 spring-cloud-dependencies …...

CTF本地靶场搭建——基于阿里云ACR实现动态flag题型的创建

接上文&#xff0c;这篇主要是结合阿里云ACR来实现动态flag题型的创建。 这里顺便也介绍一下阿里云的ACR服务。 阿里云容器镜像服务&#xff08;简称 ACR&#xff09;是面向容器镜像、Helm Chart 等符合 OCI 标准的云原生制品安全托管及高效分发平台。 ACR 支持全球同步加速、…...

【面试经典150题】删除有序数组中的重复项

目录 一.删除有序数组中的重复项 一.删除有序数组中的重复项 题目如上图所示&#xff0c;这里非严格递增排序的定义是数字序列&#xff0c;其中相邻的数字可以相等&#xff0c;并且数字之间的差值为1。 这题我们依旧使用迭代器进行遍历&#xff0c;比较当前的数据是否与下一个数…...

太阳能辐射整车综合性能环境试验舱

产品别名 步入式恒温恒湿试验箱、步入式温湿度试验箱、温度试验室、模拟环境试验室、大型恒温恒湿箱、步入式高低温湿热交变试验箱、大型高低温箱、步入式老化箱、恒温恒湿试验房、步入式高低温试验箱. 整车综合性能环境试验舱:整车综合性能环境试验舱:主要用于整车高低温存放…...

JS脚本打包成一个 Chrome 扩展(CRX 插件)

受这篇博客 如何把CSDN的文章导出为PDF_csdn文章怎么导出-CSDN博客 启发&#xff0c;将 JavaScript 代码打包成一个 Chrome 扩展&#xff08;CRX 插件&#xff09;。 步骤&#xff1a; 1.创建必要的文件结构和文件&#xff1a; manifest.jsonbackground.jscontent.js 2.编写…...

js事件对象

js事件对象概念说明 在JavaScript中&#xff0c;事件对象是在事件触发时由浏览器自动创建的一个对象。它包含了与事件相关的信息&#xff0c;例如触发事件的元素、事件类型、鼠标的坐标等。 可以通过事件处理函数的第一个参数来访问事件对象。例如&#xff0c;在一个鼠标点击…...

希捷硬盘怎么恢复数据? 5 个免费希捷数据恢复软件

希捷已迅速成为全球最大的数字存储提供商。许多人选择并使用希捷外置硬盘来存储他们的媒体文件、学校或工作文件以及其他重要数据。有时&#xff0c;希捷硬盘中的数据会丢失。 如果您丢失了希捷硬盘上的数据&#xff0c;请不要惊慌。在专业的希捷数据恢复软件的帮助下&#xf…...

Nvidia Jetson/Orin +FPGA+AI大算力边缘计算盒子:京东无人配送机器人

电商巨头京东已选用NVIDIA Jetson AGX Xavier 平台&#xff0c;作为下一代自主配送机器人核心AI算力。 在过去的几十年中&#xff0c;中国占据了全球40&#xff05;以上的电商交易——每年约为千亿美元。根据麦肯锡全球研究院的数据&#xff0c;这一数字已经高于法国、德国、…...

STM32作业实现(七)OLED显示数据

目录 STM32作业设计 STM32作业实现(一)串口通信 STM32作业实现(二)串口控制led STM32作业实现(三)串口控制有源蜂鸣器 STM32作业实现(四)光敏传感器 STM32作业实现(五)温湿度传感器dht11 STM32作业实现(六)闪存保存数据 STM32作业实现(七)OLED显示数据 STM32作业实现(八)触摸按…...

elementui el-tooltip文字提示组件弹出层内容格式换行处理

1、第一种 1.1 效果图 1.2、代码 <template><div class"wrapper"><el-tooltip class"content" effect"dark" placement"top"><div slot"content"><div v-html"getTextBrStr(text)"&…...

Python3 笔记:每天一个函数——str.join()

join() &#xff1a;连接字符串数组。将字符串、元组、列表中的元素以指定的字符&#xff08;分隔符&#xff09;连接生成一个新的字符串。 语法&#xff1a;sep.join(seq) 参数说明&#xff1a; sep&#xff1a;分隔符。可以为空。 seq&#xff1a;要连接的元素序列、字符串…...

深入解析Python中的None与null:它们真的不同吗?

标题&#xff1a;深入解析Python中的None与null&#xff1a;它们真的不同吗&#xff1f; 摘要 在Python编程中&#xff0c;None是一个常见的概念&#xff0c;而null则通常与Python之外的语言相关。尽管None和null在某些语言中可以互换使用&#xff0c;但在Python中&#xff0…...

论文作图之高压缩比导出PDF

笔者使用Adobe Illustrator 2023创建可编辑pdf图&#xff0c;按照默认的导出设置保存pdf文件时&#xff0c;得到的图存储很大。为了解决存储过大且还保留一定编辑功能的问题&#xff0c;作者实践出了一种导出pdf的设置方法。 首先在AI中点击文件->存储为&#xff0c;点击保…...

SpringBoot的启动流程

SpringBoot的启动流程 主要包括初始化配置、创建应用程序上下文、刷新上下文以及通知监听者等步骤。 下面将详细探讨SpringBoot的启动流程&#xff0c;以了解其背后的工作原理和机制&#xff1a; 初始化配置&#xff1a;当main方法被调用时&#xff0c;首先通过类加载器读取cla…...

Kubernetes资源调度策略及实现机制

目录 一、资源调度策略 1.默认调度器&#xff08;Default Scheduler&#xff09; 2.自定义调度器&#xff08;Custom Scheduler&#xff09; 3.亲和性与反亲和性&#xff08;Affinity and Anti-Affinity&#xff09; 4.污点与容忍&#xff08;Taint and Tolerations&#…...

finetuning大模型准备(基于Mac环境)

为finetuning进行的热身准备&#xff0c;涉及周边的软件工具&#xff0c;方法。 问题1&#xff1a;finetuning过程较长&#xff0c;采用系统自带命令行没有后台&#xff0c;前台被杀后&#xff0c;容易造成训练失败。 解决方法&#xff1a; tmux可以开启后台训练 问题2&…...

js检验一个字符串是否是正确时间格式的工具方法

js检验一个字符串是否是正确时间格式的工具方法 (()> {/*** 检验字符串是否为时间格式* param {String} date 需要检验的时间格式* returns true 为时间格式&#xff0c;false 为非时间格式*/const isTimaFormat (date) > {if(!date) return false;try{const tempTime …...

大型制造业集团IT信息化总体规划方案(65页PPT)

方案介绍&#xff1a; 本大型制造业集团IT信息化总体规划方案旨在通过构建先进、高效、稳定的IT信息化系统&#xff0c;支撑集团各业务领域的运营和管理需求&#xff0c;促进集团整体运营效率和竞争力的提升。通过实施本项目&#xff0c;集团将能够更好地应对市场变化和客户需…...

【LIN】STM32新能源汽车LIN通信实现过程

【LIN】STM32新能源汽车LIN通信实现过程 文章目录 前言一、软件二、接线图三、硬件原理图四、上位机五、PICO示波器串行解码1.软件中的LIN波特率设置-192002.PIC设置3.PIC串行解码 六.引用总结 前言 【电机控制】直流有刷电机、无刷电机汇总——持续更新 使用工具&#xff1a;…...

【LeetCode:575. 分糖果+ 哈希表】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…...

全文检索-ElasticSearch

1.基本概念 1.Index索引 动词&#xff1a;相当于MySQL中的insert&#xff1b; 名词&#xff1a;相当于MySQL中的DataBase&#xff1b; 2.Type&#xff08;类型&#xff09; 在Index&#xff08;索引&#xff09;中&#xff0c;可以定义一个或多个类型 类似于MySQL中的Tab…...

C编程惯用法:深入剖析与实战指南

C编程惯用法&#xff1a;深入剖析与实战指南 在C语言编程的浩瀚海洋中&#xff0c;掌握一些惯用法对于提升代码质量、增强可读性以及降低出错率至关重要。本文将从四个方面、五个方面、六个方面和七个方面&#xff0c;详细剖析C编程中的惯用法&#xff0c;帮助您更好地理解和应…...

MySQL数据表的设计

实际工程中, 对于数据表的设计和创建, 我们遵循以下步骤: 首先确定实体, 找到关键名词, 提取关键信息, 设计表有哪些列, 每一列是什么. (有几个实体, 一般就创建几个表, 一般一个表对应一个实体) 实体之间的关系: 1. 一对一关系 例如: 一个学生, 只能有一个账号; 一个账号只…...

Flutter开发效率提升1000%,Flutter Quick教程之对写好的Widget进行嵌套

通常写代码的时候&#xff0c;我们是先写好外面的Widget&#xff0c;再写里面的Widget。但是&#xff0c;也有的时候&#xff0c;我们写好了一个Widget&#xff0c;但是我们觉得有必要再在外面嵌套一个Widget&#xff0c;这时候应该怎么做呢&#xff1f;&#xff08;还有其他方…...

2020编程语言排序:探索编程界的热门与趋势

2020编程语言排序&#xff1a;探索编程界的热门与趋势 在数字时代的浪潮中&#xff0c;编程语言作为构建数字世界的基石&#xff0c;其流行度和影响力不容忽视。2020年&#xff0c;各大编程语言在各自的领域里展现出独特的魅力和实力。本文将从四个方面、五个方面、六个方面和…...

提高工作效率的招数

自己的工作效率为啥比别人低&#xff0c;因为不会使用工具&#xff0c;这就是一个大冤种。 1.血泪教训&#xff0c;写代码调用第三方接口的时候已经要打印调用日志&#xff0c;不然扯皮真的难搞。 2.pg 上测试或的时候由于schema 错误mybatis会给你报空指针一样&#xff0c;还…...

css特殊效果和页面布局

特殊效果 圆角边框&#xff1a;div{border-radius: 20px 10px 50px 30px;} 四个属性值按顺时针排列&#xff0c;左上的1/4圆半径为20px&#xff0c;右上10&#xff0c;右下50&#xff0c;左下30。 div{border-radius: 20px;} 四角都为20px。 div{border-radius: 20px 10…...

JavaScript中对象的增删改查

1. 增&#xff08;添加属性&#xff09; let obj {}; // 添加一个属性 obj.name John Doe; // 或者使用方括号语法添加属性&#xff08;这对于动态属性名很有用&#xff09; let propName age; obj[propName] 30; console.log(obj); // 输出: { name: John Doe, …...

技术周总结 2024.05.27~06.02(java bean冲突 软件工程)

文章目录 一、05.28 周二1.1&#xff09;问题01&#xff1a;java 引用的jar包中bean名称冲突了&#xff0c;怎么解决&#xff1f;1.2&#xff09;问题02&#xff1a;使用SparkSession将json字符串转成 DataFrame 二、06.01 周六2.1&#xff09;问题01&#xff1a;系统架构师考试…...

「前端+鸿蒙」核心技术HTML5+CSS3(八)

1、网站布局详解 网站布局是前端开发中的核心概念之一,它决定了网页的视觉结构和用户浏览的逻辑顺序。以下是几种常见的布局方式及其代码示例: 固定布局: 固定布局通常具有固定的宽度和高度,适用于传统的桌面视图。 <!DOCTYPE html> <html> <head><…...

15届蓝桥杯决赛,java b组,蒟蒻赛时所写的题思路

这次题的数量是10题&#xff0c;初赛是8题&#xff0c;还多了两题&#xff0c;个人感觉java b组的题意还是比较清晰的&#xff08;不存在读不懂题的情况&#xff09;&#xff0c;但是时间感觉还是不够用&#xff0c;第4题一开始不会写&#xff0c;后面记起来写到结束也没调出来…...

2024蓝桥杯国赛C++研究生组游记+个人题解

Day0 开始复习&#xff0c;过了一遍大部分板子 本来打算再学一遍SAM&#xff0c;但是想到去年考了字符串大题今年应该不会再考了吧。。 过了一遍数据结构和图论&#xff0c;就1点了 两点的时候还没睡着&#xff0c;舍友打游戏好像打到2点过。。 Day1 相当困 第一题&…...

C#WPF数字大屏项目实战07--当日产量

1、第2列布局 第2列分三行&#xff0c;第一行分6列 2、当日产量布局 3、产量数据布局 运行效果 4、计划产量和完成度 运行效果 5、良品率布局 1、添加用户控件 2、用户控件绘制圆 2、使用用户控件 3、运行效果 4、注意点 这三个数值目前是静态的&#xff0c;可以由后台程序项…...

MyBatis源码分析--02:SqlSession建立过程

我们再来看看MyBatis使用流程&#xff1a; InputStream inputStream Resources.getResourceAsStream("myBatis_config.xml"); SqlSessionFactory sqlSessionFactory new SqlSessionFactoryBuilder().build(inputStream); SqlSession session sqlSessionFactory.op…...

SOUI Combobox 实现半透明弹出下拉框

SOUI默认情况下combobox的弹出框不是半透明的&#xff0c;这个时候如果背景透明时&#xff0c;滚动条会出现黑色背景&#xff0c;这个时候只需要在在combobox下添加一个子节点 <dropdownStyle translucent"1"></dropdownStyle> 这样一个窗口默认即实现…...

Python 猜数系统 PyQt框架 有GUI界面 (源码在最后)【含Python源码 MX_002期】

一、系统简介 猜数界面是一个基于PyQt框架创建的简单图形用户界面&#xff08;GUI&#xff09;&#xff0c;用于让用户参与猜数字游戏。简要介绍一下界面的各个部分&#xff1a; 游戏开始按钮&#xff1a;点击此按钮开始游戏。在点击前&#xff0c;需要在文本框中输入参与游戏…...

npm install pubsub-js报错的解决汇总

我在练习谷粒商城P83时&#xff0c;选择分类时触发向后端请求选择分类catId绑定的品牌数据&#xff0c;发现前端控制台报错&#xff1a; "PubSub is not definded",找不到pubsub。 因为缺少pubsub包&#xff0c;所以开始安装此包。 于是在网上一顿搜索猛如虎&…...

nuxt2:自定义指令 / v-xxx / directives / 理解 / 使用方法 / DEMO

一、理解自定义指令 在 vue 中提供了一些对于页面和数据更为方便的输出&#xff0c;这些操作就叫做指令&#xff0c;以 v-xxx 表示&#xff0c;比如 html 页面中的属性 <div v-xxx ></div>。自定义指令很大程度提高了开发效率&#xff0c;提高了工程化水平&#x…...