vì câu hỏi này và một số câu trả lời đã hơn năm tuổi, hãy để tôi chia sẻ giải pháp của mình. Đây là phần tiếp theo và hiện đại hóa cho câu trả lời từ @oyenigun
CẬP NHẬT:
Ở cuối bài viết này, tôi đã thêm một triển khai thay thế bằng cách sử dụng phần mở rộng Fragment trừu tượng không liên quan đến Activity, điều này sẽ hữu ích cho bất kỳ ai có hệ thống phân cấp phân đoạn phức tạp hơn liên quan đến các đoạn lồng nhau yêu cầu hành vi ngược khác nhau.
Tôi cần phải thực hiện điều này vì một số đoạn tôi sử dụng có chế độ xem nhỏ hơn mà tôi muốn loại bỏ bằng nút quay lại, chẳng hạn như chế độ xem thông tin nhỏ bật lên, v.v., nhưng điều này tốt cho bất kỳ ai cần ghi đè hành vi của nút quay lại bên trong các mảnh.
Đầu tiên, xác định một Giao diện
public interface Backable {
boolean onBackPressed();
}
Giao diện này, mà tôi gọi Backable
(tôi là người gắn bó để đặt tên cho các quy ước), có một phương thức duy nhất onBackPressed()
phải trả về một boolean
giá trị. Chúng ta cần thực thi một giá trị boolean bởi vì chúng ta sẽ cần phải biết nếu nhấn nút quay lại đã "hấp thụ" sự kiện trở lại. Trở về true
nghĩa là nó có, và không cần thêm hành động nào, nếu không, false
nói rằng hành động quay lại mặc định vẫn phải diễn ra. Giao diện này phải là tệp riêng của nó (tốt nhất là trong một gói riêng có têninterfaces
). Hãy nhớ rằng, tách các lớp học của bạn thành các gói là thực hành tốt.
Thứ hai, tìm đoạn đầu
Tôi đã tạo một phương thức trả về Fragment
đối tượng cuối cùng trong ngăn xếp phía sau. Tôi sử dụng thẻ ... nếu bạn sử dụng ID, hãy thực hiện các thay đổi cần thiết. Tôi có phương thức tĩnh này trong một lớp tiện ích liên quan đến các trạng thái điều hướng, v.v ... nhưng tất nhiên, đặt nó ở nơi phù hợp nhất với bạn. Để chỉnh sửa, tôi đã đặt tôi vào một lớp được gọi NavUtils
.
public static Fragment getCurrentFragment(Activity activity) {
FragmentManager fragmentManager = activity.getFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
String lastFragmentName = fragmentManager.getBackStackEntryAt(
fragmentManager.getBackStackEntryCount() - 1).getName();
return fragmentManager.findFragmentByTag(lastFragmentName);
}
return null;
}
Hãy chắc chắn rằng số lượng ngăn xếp trở lại lớn hơn 0, nếu không ArrayOutOfBoundsException
có thể được ném vào thời gian chạy. Nếu nó không lớn hơn 0, trả về null. Chúng tôi sẽ kiểm tra giá trị null sau ...
Thứ ba, thực hiện trong một mảnh
Thực hiện Backable
giao diện trong bất kỳ đoạn nào mà bạn cần ghi đè hành vi của nút quay lại. Thêm phương thức thực hiện.
public class SomeFragment extends Fragment implements
FragmentManager.OnBackStackChangedListener, Backable {
...
@Override
public boolean onBackPressed() {
// Logic here...
if (backButtonShouldNotGoBack) {
whateverMethodYouNeed();
return true;
}
return false;
}
}
Trong phần onBackPressed()
ghi đè, đặt bất kỳ logic nào bạn cần. Nếu bạn muốn nút quay lại không bật ngăn xếp phía sau (hành vi mặc định), hãy trả về true , rằng sự kiện trở lại của bạn đã được hấp thụ. Nếu không, trả lại sai.
Cuối cùng, trong Hoạt động của bạn ...
Ghi đè onBackPressed()
phương thức và thêm logic này vào nó:
@Override
public void onBackPressed() {
// Get the current fragment using the method from the second step above...
Fragment currentFragment = NavUtils.getCurrentFragment(this);
// Determine whether or not this fragment implements Backable
// Do a null check just to be safe
if (currentFragment != null && currentFragment instanceof Backable) {
if (((Backable) currentFragment).onBackPressed()) {
// If the onBackPressed override in your fragment
// did absorb the back event (returned true), return
return;
} else {
// Otherwise, call the super method for the default behavior
super.onBackPressed();
}
}
// Any other logic needed...
// call super method to be sure the back button does its thing...
super.onBackPressed();
}
Chúng tôi nhận được đoạn hiện tại trong ngăn xếp phía sau, sau đó chúng tôi kiểm tra null và xác định xem nó có thực hiện Backable
giao diện của chúng tôi không . Nếu có, xác định xem sự kiện đã được hấp thụ. Nếu vậy, chúng tôi đã hoàn thành onBackPressed()
và có thể trở lại. Nếu không, hãy coi nó như một ấn trở lại bình thường và gọi siêu phương thức.
Tùy chọn thứ hai để không liên quan đến Hoạt động
Đôi khi, bạn không muốn Activity xử lý việc này chút nào và bạn cần xử lý trực tiếp trong phân đoạn. Nhưng ai nói bạn không thể có Mảnh vỡ với API nhấn? Chỉ cần mở rộng đoạn của bạn đến một lớp mới.
Tạo một lớp trừu tượng mở rộng Fragment và thực hiện View.OnKeyListner
giao diện ...
import android.app.Fragment;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
public abstract class BackableFragment extends Fragment implements View.OnKeyListener {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(this);
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
onBackButtonPressed();
return true;
}
}
return false;
}
public abstract void onBackButtonPressed();
}
Như bạn có thể thấy, bất kỳ đoạn nào mở rộng BackableFragment
sẽ tự động thu lại các lần nhấp bằng View.OnKeyListener
giao diện. Chỉ cần gọi onBackButtonPressed()
phương thức trừu tượng từ bên trong onKey()
phương thức đã triển khai bằng cách sử dụng logic tiêu chuẩn để phân biệt nhấn nút quay lại. Nếu bạn cần đăng ký các lần bấm phím khác với nút quay lại, chỉ cần đảm bảo gọi super
phương thức khi ghi đè onKey()
vào đoạn của bạn, nếu không bạn sẽ ghi đè hành vi trong phần trừu tượng.
Sử dụng đơn giản, chỉ cần mở rộng và thực hiện:
public class FragmentChannels extends BackableFragment {
...
@Override
public void onBackButtonPressed() {
if (doTheThingRequiringBackButtonOverride) {
// do the thing
} else {
getActivity().onBackPressed();
}
}
...
}
Vì onBackButtonPressed()
phương thức trong siêu lớp là trừu tượng, nên một khi bạn mở rộng, bạn phải thực hiện onBackButtonPressed()
. Nó trả về void
vì nó chỉ cần thực hiện một hành động trong lớp phân đoạn và không cần chuyển tiếp sự hấp thụ của báo chí trở lại Hoạt động. Đảm bảo bạn gọi onBackPressed()
phương thức Activity nếu bất cứ điều gì bạn đang làm với nút quay lại không yêu cầu xử lý, nếu không, nút quay lại sẽ bị tắt ... và bạn không muốn điều đó!
Hãy cẩn thận
Như bạn có thể thấy, điều này đặt người nghe chính vào chế độ xem gốc của đoạn và chúng ta sẽ cần phải tập trung vào nó. Nếu có các văn bản chỉnh sửa liên quan (hoặc bất kỳ chế độ xem lấy nét tập trung nào khác) trong đoạn của bạn mở rộng lớp này, (hoặc các đoạn hoặc khung nhìn bên trong khác có cùng), bạn sẽ cần xử lý riêng điều đó. Có một bài viết hay về việc mở rộng EditText để mất tập trung vào báo chí trở lại.
Tôi hi vọng ai đó thấy nó hữu ích. Chúc mừng mã hóa.