JavaFragment的简单使用
了解Fragment作用及特点
1、Fragment作为Activity界面的一部分组成出现;
2、可以在一个Activity中同时出现多个Fragment,并且一个Fragment亦可在多个Activity中使用;
3、在Activity运行过程中,可以添加、移除或者替换Fragment(add()、remove()、replace());
4、Fragment可以响应自己的输入事件,并且有自己的生命周期,当然,它们的生命周期直接受其所属的宿主Activity的生命周期控制。
现实需求
手机这样设置页面样式不辣眼
平板这样设置就稍微有点辣眼
因此我们可以使用Fragment让他们显示到一个屏幕上
Fragment生命周期
和Acitivity的关系
Fragment创建方法
静态加载(布局里加载)
<!-- 静态加载-->
<!-- 必须有ID属性-->
<!-- 必须有name属性-->
<fragment
android:id="@+id/fram"
android:name="com.qingsu.fragmentdemo.fragment.MyFragmentOne"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
动态加载
创建一个Fragment MyFragmentOne
Fragment创建
//获取FragmentManager
FragmentManager fragmentManager = getSupportFragmentManager();
//创建事务FragmentTransaction
FragmentTransaction transaction = fragmentManager.beginTransaction();
//添加一个Fragment到事务里
//第一个参数 要添加到的位置 第二个参数
MyFragmentOne myFragmentOne = new MyFragmentOne();
//添加一个碎片
transaction.add(R.id.fram,myFragmentOne);
//提交事务
transaction.commit();
Fragment切换的方法
添加
transaction.add(R.id.fragment,fragmentOne);
移除
transaction.remove(fragmentOne);
替换
transaction.replace(R.id.fragment,fragmentFour);
隐藏
transaction.hide(fragmentFour);
显示
transaction.show(fragmentFour);
演示
布局
主布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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"
tools:context=".MyFragmentActivity"
>
<LinearLayout
android:id="@+id/liner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:weightSum="5"
>
<Button
android:id="@+id/bt_add"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="增加"
/>
<Button
android:id="@+id/bt_move"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="移除"
/>
<Button
android:id="@+id/bt_repalce"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="替换"
/>
<Button
android:id="@+id/bt_hide"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="隐藏"
/>
<Button
android:id="@+id/bt_show"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="显示"
/>
</LinearLayout>
<FrameLayout
android:id="@+id/fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/liner"
>
</FrameLayout>
</RelativeLayout>
FrameLayout(其中一个)
<?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"
tools:context=".fragment.FragmentTwo"
>
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#2196F3"
android:layout_gravity="top"
android:text="这是第二个哈哈哈"
/>
</FrameLayout>
代码
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.qingsu.fragmentdemo.fragment.FragmentFour;
import com.qingsu.fragmentdemo.fragment.FragmentThree;
import com.qingsu.fragmentdemo.fragment.FragmentTwo;
import java.util.ArrayList;
public class MyFragmentActivity extends AppCompatActivity implements View.OnClickListener {
Button mBtAdd,mBtMove,mBtRepalce,mBtHide,mBtShow;
FragmentThree fragmentThree = new FragmentThree();
FragmentTwo fragmentTwo= new FragmentTwo();
FragmentFour fragmentFour = new FragmentFour();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
initView();
mBtAdd.setOnClickListener(this);
mBtMove.setOnClickListener(this);
mBtRepalce.setOnClickListener(this);
mBtHide.setOnClickListener(this);
mBtShow.setOnClickListener(this);
}
private void initView(){
mBtAdd = findViewById(R.id.bt_add);
mBtMove = findViewById(R.id.bt_move);
mBtRepalce = findViewById(R.id.bt_repalce);
mBtHide = findViewById(R.id.bt_hide);
mBtShow = findViewById(R.id.bt_show);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.bt_add:
add();
break;
case R.id.bt_move:
remove();
break;
case R.id.bt_repalce:
replace();
break;
case R.id.bt_hide:
hidin();
break;
case R.id.bt_show:
show();
break;
default:
break;
}
}
//添加
private void add(){
//获取Fragment管理器
FragmentManager manager = getSupportFragmentManager();
//开启事务
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.fragment,fragmentTwo);
transaction.add(R.id.fragment,fragmentThree);
//提交事务
transaction.commit();
}
//移除
private void remove(){
//获取Fragment管理器
FragmentManager manager = getSupportFragmentManager();
//开启事务
FragmentTransaction transaction = manager.beginTransaction();
transaction.remove(fragmentThree);
transaction.commit();
}
//替换
private void replace(){
//获取Fragment管理器
FragmentManager manager = getSupportFragmentManager();
//开启事务
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.fragment,fragmentFour);
transaction.commit();
}
//隐藏
private void hidin(){
//获取Fragment管理器
FragmentManager manager = getSupportFragmentManager();
//开启事务
FragmentTransaction transaction = manager.beginTransaction();
transaction.hide(fragmentFour);
transaction.commit();
}
//显示
private void show(){
//获取Fragment管理器
FragmentManager manager = getSupportFragmentManager();
//开启事务
FragmentTransaction transaction = manager.beginTransaction();
transaction.show(fragmentFour);
transaction.commit();
}
}
效果
数据传递
Activity向Fragment setArguments方法 或者其他
Activity
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
Bundle bundle = new Bundle();
bundle.putString("name","我的电话响了");
DataFragment dataFragment = new DataFragment();
dataFragment.setArguments(bundle);
transaction.add(R.id.fragment,dataFragment);
transaction.commit();
Fragment
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
if(bundle!=null){
name = bundle.getString("name");
}
}
Fragment向Activity
接口回调 父类类型接收子类对象 调用子父类中共有的方法
接口
public interface IChangDemo {
void change(int num);
}
Activity 接口的子类
@Override
public void chang(String title) {
Log.d("TAG",title);
}
//将Activity 自己值传递给Fragment 用于接口类型变量的接收
dataFragment.setiChangData(this);
Fragment
//声明一个接口变量
private IChangData iChangData;
//接收子类对象
public void setiChangData(IChangData iChangData) {
this.iChangData = iChangData;
}
//通过接口 调用Activity的chang方法并传递name值
iChangData.chang(name);
Fragment向Fragment
以Activity为媒介 传递
限定符
为了适配不同屏幕大小的android手机或android平板,有时候就需要利用限定符来为不同的屏幕设定不同的布局文件。
常用的限定符
屏幕特性 | 限定符 | 描述 |
---|---|---|
屏幕尺寸 | small | 小屏幕 |
normal | 基准屏幕 | |
large | 大屏幕 | |
xlarge | 超大屏幕 | |
屏幕密度 | ldpi | <=120dpi |
mdpi | <= 160dpi | |
hdpi | <= 240dpi | |
xhdpi | <= 320dpi | |
xxhdpi | <= 480dpi | |
xxhdpi | <= 640dpi(只用来存放icon) | |
nodpi | 与屏幕密度无关的资源.系统不会针对屏幕密度对其中资源进行压缩或者拉伸 | |
tvdpi | 介于mdpi与hdpi之间,特定针对213dpi,专门为电视准备的,手机应用开发不需要关心这个密度值. | |
屏幕方向 | land | 横向 |
port | 纵向 | |
屏幕宽高比 | long | 比标准屏幕宽高比明显的高或者宽的这样屏幕 |
notlong | 和标准屏幕配置一样的屏幕宽高比 |
限定符是用于查找文件夹的
比如layout_large文件夹和layout文件夹下都有一个名为activity_main的布局文件 系统就会根据手机屏幕的大小自动匹配相应的布局
但是到底什么是大呢?我答不出来
因此我们一般使用最小宽度限定符 比如 sw700dp 当屏幕的宽度超过700dp时会使用其下文件下的布局文件
屏幕特性 | 限定符 | 描述 |
---|---|---|
最小宽度限定符 | sw< N >dp sw600dp | 屏幕的最小尺寸,就是屏幕可用区域的最小尺寸,是指屏幕可用高度或宽度的最小值(你可以默认是屏幕的最小宽度).你能用这个限定符确保,无论屏幕方向如何,这个限定符修饰下的布局需要的屏幕最小尺寸是Ndp.例如,如果你的布局在运行时需要的最小屏幕宽度是600dp,则你可以利用这个限定符创建布局资源目录res/layout-sw600dp.只有当屏幕的最小宽度或最小高度是600dp时,系统才会使用这些布局文件或者资源文件.最小屏幕宽度是固定设备的特有屏幕尺寸,当屏幕方向发生变化时,设备的最小宽度值不变.设备的最小宽度值要考虑屏幕的尺寸和系统UI.例如,如果在屏幕上有一些系统持久化UI元素,则系统的最小宽度值要比实现的屏幕尺寸小一些,因为这些系统的UI元素你的应用是无法使用到的.当你使用之前的广义限定符是,你可以定义连续的一系列限定符.用最小宽度来决定广义屏幕尺寸是有意义的,是因为宽度是影响你UI设计的关键因素.UI在竖直方向上会经常滚动,但是在水平方向上往往是固定的布局.可见不论是适配手机或者平板,宽度往往都是布局的关键因素.因此,你需要关心你手机上的最小宽度值. |
屏幕可用宽度 | w< N >dp w720p | 指定资源使用时需要的最小宽度.当屏幕方向发生变化时,系统会调整这个值,使其始终为你UI显示的宽度.这个属性经常被用来判断当前是否需要显示多屏布局,因为哪怕用户当前正在使用平板,你也可能不希望用户在平板竖屏时显示多个屏幕的布局样式.这时,你就可以使用这个限定符来标明你布局需要的最小宽度 |
屏幕可用高度 | h< N >dp | 标明资源使用时需要的最小高度.当屏幕发生旋转时,系统会自动选择当前大的一方作为高度值.大部分应用很少需要这个限定符,因此不做过多讲解 |
实现新闻应用 平板是单页显示 手机是双页显示
主页面MainActivity
单页布局 activity_main 只加载一个Fragment
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/news_title_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="@+id/news_title_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</FrameLayout>
双页布局 activity_main layout-sw600dp文件夹下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/news_content_layout"
>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/news_title_fragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
</FrameLayout>
<FrameLayout
android:id="@+id/news_content_fragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3">
</FrameLayout>
</LinearLayout>
</LinearLayout>
代码
单页点击新闻列表条目显示内容碎片 双页则跳转新的页面
package com.qingsu.newstwo;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
public class MainActivity extends AppCompatActivity implements IShowFrgment{
NewsTitleFragment newsTitleFragment;
NewsContentFragment newsContentFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addFragment();
}
private void addFragment(){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
newsTitleFragment = new NewsTitleFragment();
fragmentTransaction.add(R.id.news_title_fragment,newsTitleFragment);
fragmentTransaction.commit();
}
@Override
public void showFrgment(News news) {
Bundle bundle = new Bundle();
newsContentFragment = new NewsContentFragment();
bundle.putString("news_title",news.getTitle());
bundle.putString("news_content",news.getContent());
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction Transaction = fragmentManager.beginTransaction();
newsContentFragment.setArguments(bundle);
Transaction.replace(R.id.news_content_fragment,newsContentFragment);
Transaction.commit();
}
}
新闻数据JavaBean容器
package com.qingsu.newstwo;
public class News {
private String title;
private String content;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
新闻内容显示接口 用于清单碎片拥有刷新新闻页面的能力
public interface IShowFrgment {
void showFrgment(News news);
}
新闻页面 标题+内容 NewsContentFragment
布局
<?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"
tools:context=".NewsContentFragment">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/layout_show"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="invisible">
<TextView
android:id="@+id/news_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:textSize="20sp" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#000" />
<TextView
android:id="@+id/news_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="15dp"
android:textSize="18sp" />
</LinearLayout>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:background="#000" />
</RelativeLayout>
</FrameLayout>
代码
package com.qingsu.newstwo;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class NewsContentFragment extends Fragment{
private View viewfragment;
private LinearLayout visibilityLayout;
private String newsTitle;
private String newsContent;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
viewfragment = inflater.inflate(R.layout.news_content_frag, container, false);
visibilityLayout = viewfragment.findViewById(R.id.layout_show);
return viewfragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
if(bundle!=null){
newsTitle = bundle.getString("news_title");
newsContent = bundle.getString("news_content");
}else {
}
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
refresh(newsTitle,newsContent);
}
private void refresh(String newsTitle, String newsContent) {
visibilityLayout.setVisibility(View.VISIBLE);
TextView newsTitleText = viewfragment.findViewById (R.id.news_title);
TextView newsContentText = viewfragment.findViewById(R.id.news_content);
newsTitleText.setText(newsTitle); // 刷新新闻的标题
newsContentText.setText(newsContent); // 刷新新闻的内容
}
}
进入的起始新闻清单NewsTitleFragment
布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/news_title_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</FrameLayout>
条目布局
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/news_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:textSize="18sp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="15dp"
android:paddingBottom="15dp"
/>
代码
加入判断 存在news_content_layout则表明是单页 不存在表示双页
package com.qingsu.newstwo;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class NewsTitleFragment extends Fragment {
private boolean isTwoPane;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.news_title_frag, container, false);
RecyclerView newsTitleRecyclerView = view.findViewById(R.id.news_title_recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
newsTitleRecyclerView.setLayoutManager(layoutManager);
NewsAdapter adapter = new NewsAdapter(getNews());
adapter.setiShowFrgment((MainActivity)getActivity());
newsTitleRecyclerView.setAdapter(adapter);
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getActivity().findViewById(R.id.news_content_layout) != null) {
isTwoPane = true; // 可以找到news_content_layout布局时,为双页模式
} else {
isTwoPane = false; // 找不到news_content_layout布局时,为单页模式
}
}
private List<News> getNews() {
List<News> newsList = new ArrayList<>();
for (int i = 1; i <= 50; i++) {
News news = new News();
news.setTitle("This is news title " + i);
news.setContent(getRandomLengthContent("This is news content " + i + ". "));
newsList.add(news);
}
return newsList;
}
private String getRandomLengthContent(String content) {
Random random = new Random();
int length = random.nextInt(20) + 1;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < length; i++) {
builder.append(content);
}
return builder.toString();
}
class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
private List<News> mNewsList;
private IShowFrgment iShowFrgment;
public void setiShowFrgment(IShowFrgment iShowFrgment) {
this.iShowFrgment = iShowFrgment;
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView newsTitleText;
public ViewHolder(View view) {
super(view);
newsTitleText = view.findViewById(R.id.news_title);
}
}
public NewsAdapter(List<News> newsList) {
mNewsList = newsList;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item, parent, false);
final ViewHolder holder = new ViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
News news = mNewsList.get(holder.getAdapterPosition());
if (isTwoPane) {
iShowFrgment.showFrgment(news);
} else {
NewsContentActivity.actionStart(getActivity(), news.getTitle(), news.getContent());
}
}
});
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
News news = mNewsList.get(position);
holder.newsTitleText.setText(news.getTitle());
}
@Override
public int getItemCount() {
return mNewsList.size();
}
}
}
双页模式所跳转的NewsContentActivity
package com.qingsu.newstwo;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
public class NewsContentActivity extends AppCompatActivity {
private NewsContentFragment newsContentFragment;
public static void actionStart(Context context, String newsTitle, String newsContent) {
Intent intent = new Intent(context, NewsContentActivity.class);
intent.putExtra("news_title", newsTitle);
intent.putExtra("news_content", newsContent);
context.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_content);
String newsTitle = getIntent().getStringExtra("news_title"); // 获取传入的新闻标题
String newsContent = getIntent().getStringExtra("news_content"); // 获取传入的新闻内容
Bundle bundle = new Bundle();
bundle.putString("news_title",newsTitle);
bundle.putString("news_content",newsContent);
newsContentFragment = new NewsContentFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction Transaction = fragmentManager.beginTransaction();
Transaction.add(R.id.news_content_fragment,newsContentFragment);
newsContentFragment.setArguments(bundle);
Transaction.commit();
}
}