事件
Android 框架中管理一个事件队列,当有事件发生时,事件就被放入到队列中。
事件会被传递到屏幕上触摸发生位置所对应的视图。除了事件通知外,该视图还会接收到一系列(取决于事件类型)关于事件性质的信息,例如用户指尖与屏幕接触点的坐标。
视图处理被传递事件,必须有事件监听器。所有用户界面组件皆派生自 Android 的 View 类,该类包含一系列事件监听器接口,每个接口都包含一个回调方法的抽象声明。
去响应一个特定类型的事件,视图必须注册合适的事件监听着,并且实现对应的回调方法。
事件监听器和回调方法
onClickListener:探测用户点击哪里然后松开,配合 onClick 方法使用,该方法会接收一个对接收事件的视图的引用作为参数。
onLongClickListener:检测用户长按一个视图一段时间,配合 onLongClick() 方法使用。
onTouchListener:检测任何形式与屏幕的接触,包括单点、多点和各种手势,配合 onTouch() 方法。
onCreateContextMenuListener:监听长按创建上下文菜单,配合 onCreateContextMenu() 方法使用,该方法传递一个菜单,这个视图接收一个事件和一个菜单对象。
onFocusChangeListener:检测当因与轨迹球或导航键交互而导致焦点从当前视图移开的情况。配合方法 onFocusChange() 。
onKeyListener:用于检测在某个视图获得焦点时,设备上的某个按键何时被按下。配合方法 onKey() 使用。
什么是 Fragment
Fragment 是应用程序用户界面中一个独立的、模块化的部分,以及与之对应的行为,它可以嵌入到 Activity 中。 在应用程序设计阶段,Fragment 可组合起来创建一个 Activity;而在应用程序运行时,Fragment 可添加到 Activity 中或从 Activity 中移除,以创建动态 Activity 中移除,以创建动态变化的用户界面。
Fragment 只能作为 Activity 的一部分使用,不能作为独立的应用程序元素实例化。 Fragment 可以被认为是一个功能性的" 子 Activity ",其生命周期与完整 Activity 的生命周期相似。
在 Fragment 中使用 ConstraintLayout 需要在 layout_width 和 height 前加 android 前缀,android:layout_width="match_parent"
如果在 Activity 的Xml文件中引入 Fragment 需要继承 FragmentActivity
,默认AppCompatActivity
即可,因为是这样的继承关系
java
package com.example.basepractice;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.FragmentActivity;
import com.example.basepractice.databinding.ActivityMainBinding;
public class MainActivity extends FragmentActivity {
public ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
ConstraintSet set = new ConstraintSet();
}
}
html
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment1"
android:name="com.example.basepractice.DemoFragment"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/button8"
app:layout_constraintEnd_toEndOf="@id/button12"
app:layout_constraintStart_toStartOf="@id/button11"
>
</androidx.fragment.app.FragmentContainerView>
<Button
android:id="@+id/button8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/button12"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toEndOf="@+id/button11"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBaseline_toBaselineOf="@+id/button8"
app:layout_constraintEnd_toStartOf="@+id/button8"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/button12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBaseline_toBaselineOf="@+id/button8"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/button8" />
</androidx.constraintlayout.widget.ConstraintLayout>
如果希望 Fragment 的尺寸通过 Activity 来设置,则需要把想指定的尺寸设置为 0dp
xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity"
>
<Button
android:id="@+id/button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="这是个Fragment的按钮"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
把 Fragment 放入Activity Java 代码中进行管理有这些步骤
1、创建一个 Fragment 类的实例
2、传递任何额外的 Intent 参数到这个实例中
3、持有一个 Fragment Manager 的实例
4、在 Fragment Manager 实例上调用 beginTransaction() 方法,返回一个 fragment transaction 实例。
5、在 fragment transaction 实例上调用 add() 方法,将用于容纳该 Fragment 的视图的资源 ID 和片段类实例作为参数传入.
6、调用 ragment transaction 的 commit() 方法。
这6步转为代码可简化至这种形态
java
DemoFragment demoFragment = new DemoFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment1, demoFragment)
.commitNow();
图形界面添加 Fragment 到 Activity 可以通过拖拽这个 FragmentContainerView
Activity 与 Fragment 的数据传递
Fragment 把数据传递给 Activity
Fragment 中:
1、定义接口和接口方法
2、声明接口类型对象
3、在 onAttach 方法中进行接口类型对象实例化
4、在某个方法中调用接口方法
代码如下
java
package com.example.basepractice;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
/**
* A simple {@link Fragment} subclass.
* Use the {@link DemoFragment#newInstance} factory method to
* create an instance of this fragment. */public class DemoFragment extends Fragment {
// 第一步:定义接口
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onDataFromFragment(String str);
}
// 第二步:定义接口变量
private OnFragmentInteractionListener mListener;
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private Button button;
public DemoFragment() {
// Required empty public constructor
}
// 第三步:实例化mListener
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
// 第四步:调用接口方法
public void buttonClick() {
String str = "Hello from Fragment";
mListener.onDataFromFragment(str);
}
/**
* Use this factory method to create a new instance of * this fragment using the provided parameters. * * @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment DemoFragment.
*/ // TODO: Rename and change types and number of parameters
public static DemoFragment newInstance(String param1, String param2) {
DemoFragment fragment = new DemoFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 加载片段布局
View rootView = inflater.inflate(R.layout.fragment_demo, container, false);
button = rootView.findViewById(R.id.button);
button.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
// buttonClick();
}
});
// Inflate the layout for this fragment
return rootView;
}
}
Activity 中:
1、创建 Fragment 实例
2、实现 Fragment 的接口方法
3、通过 Fragment 实例调用实例方法,这个实例方法中会调用 Fragment 的接口方法
代码如下
java
package com.example.basepractice;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.example.basepractice.databinding.ActivityMainBinding;
public class MainActivity extends FragmentActivity implements DemoFragment.OnFragmentInteractionListener {
public ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
// 第一步:获取fragment实例
DemoFragment demoFragment = new DemoFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment1, demoFragment)
.commitNow();
// 第三步:调用接口方法
demoFragment.buttonClick();
}
// 第二步:实现接口方法
@Override
public void onDataFromFragment(String str) {
Log.i("TAG", "onDataFromFragment: " + str);
}
}
Activity 把数据传递给 Fragment
以下这种方法也适用于 xml 文件中包含 Fragment 的情况
1、在 Fragment 中定义公开的接收方法
2、在 Activity 中通过 Fragment 实例调用这个公开的方法传值
代码如下
java
package com.example.basepractice;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
/**
* A simple {@link Fragment} subclass.
* Use the {@link DemoFragment#newInstance} factory method to
* create an instance of this fragment. */public class DemoFragment extends Fragment {
// 第一步:定义接口
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onDataFromFragment(String str);
}
// 第二步:定义接口变量
private OnFragmentInteractionListener mListener;
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private Button button;
public DemoFragment() {
// Required empty public constructor
}
// 第三步:实例化mListener
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
// 第四步:调用接口方法
public void buttonClick() {
String str = "Hello from Fragment";
mListener.onDataFromFragment(str);
}
/**
* Use this factory method to create a new instance of * this fragment using the provided parameters. * * @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment DemoFragment.
*/ // TODO: Rename and change types and number of parameters
public static DemoFragment newInstance(String param1, String param2) {
DemoFragment fragment = new DemoFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
// 用于接收来自Activity的数据
public void receiveDataFromActivity(String message) {
Log.i("fragment", "receiveDataFromActivity: " + message);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() == null) {
Log.i("demoFragment", "onCreate: Arguments are null");
}
// mParam1 = getArguments().getString(ARG_PARAM1);
// mParam2 = getArguments().getString(ARG_PARAM2);
// String message = getArguments().getString("message");
// Log.i("fragment", "onCreate: " + message);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 加载片段布局
View rootView = inflater.inflate(R.layout.fragment_demo, container, false);
button = rootView.findViewById(R.id.button);
button.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
// buttonClick();
}
});
if (getArguments() == null) {
Log.i("demoFragment", "onCreate: Arguments are null");
}
// Inflate the layout for this fragment
return rootView;
}
}
java
package com.example.basepractice;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.example.basepractice.databinding.ActivityMainBinding;
public class MainActivity extends FragmentActivity implements DemoFragment.OnFragmentInteractionListener {
public ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
FragmentManager fragmentManager = getSupportFragmentManager();
DemoFragment demoFragment = (DemoFragment) fragmentManager.findFragmentById(R.id.fragment1);
if (demoFragment == null) {
Log.i("Tag", "onCreate: 空");
} else {
// 传递数据给fragment
demoFragment.receiveDataFromActivity("Activity 的数据");
}
}
void fragmentData2Activity() {
// 第一步:获取fragment实例
DemoFragment demoFragment = new DemoFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment1, demoFragment)
.commitNow();
// 第三步:调用接口方法
demoFragment.buttonClick();
}
// 第二步:实现接口方法
@Override
public void onDataFromFragment(String str) {
Log.i("TAG", "onDataFromFragment: " + str);
}
}
ViewModel 方式 Activity 与 Fragment 的数据传递
先安装依赖
arduino
dependencies {
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7'
}
定义 ViewModel , 注意这里的 getter 和 setter 不是传统的 getter 和 setter ,这种是经过 MutableLiveData 检测可避免一些问题
Java
package com.example.basepractice;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class DataViewModel extends ViewModel {
private MutableLiveData<String> shareData = new MutableLiveData<>();
public MutableLiveData<String> getData() {
return shareData;
}
public void setData(String data) {
shareData.setValue(data);
}
}
Activity 中
Java
package com.example.basepractice;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.ViewModelProvider;
import com.example.basepractice.databinding.ActivityMainBinding;
public class MainActivity extends FragmentActivity implements DemoFragment.OnFragmentInteractionListener {
public ActivityMainBinding binding;
private DataViewModel dataViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dataViewModel = new ViewModelProvider(this).get(DataViewModel.class);
dataViewModel.setData("来自Activity的数据");
}
}
Fragment 中
Java
package com.example.basepractice;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* A simple {@link Fragment} subclass.
* Use the {@link ViewModelFragment#newInstance} factory method to
* create an instance of this fragment. */public class ViewModelFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private TextView textView;
private DataViewModel dataViewModel;
public ViewModelFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of * this fragment using the provided parameters. * * @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment ViewModelFragment.
*/ // TODO: Rename and change types and number of parameters
public static ViewModelFragment newInstance(String param1, String param2) {
ViewModelFragment fragment = new ViewModelFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 加载片段布局
View rootView = inflater.inflate(R.layout.fragment_view_model, container, false);
textView = rootView.findViewById(R.id.textView);
dataViewModel = new ViewModelProvider(requireActivity()).get(DataViewModel.class);
dataViewModel.getData().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(String s) {
textView.setText(s);
Log.i("ViewModelFragment", "onChanged: " + s);
}
});
// Inflate the layout for this fragment
return rootView;
}
}
html
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="40dp"
android:textSize="20sp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:id="@+id/textView"
>
</TextView>
</androidx.constraintlayout.widget.ConstraintLayout>
运行效果