Làm cách nào để ngăn thanh trạng thái và thanh điều hướng hoạt hình trong khi chuyển cảnh hoạt hình cảnh hoạt động?


127

Đầu tiên, nền thanh trạng thái của tôi được đặt thành màu nâu sẫm và nền thanh điều hướng của tôi có màu đen mặc định. Tôi đang sử dụng chủ đề ánh sáng Vật liệu.

Tôi đang bắt đầu một hoạt động mới bằng cách sử dụng ActivityOptions.makeSceneTransitionAnimationcác chuyển tiếp mặc định và tôi nhận thấy rằng cả thanh trạng thái và thanh điều hướng nhanh chóng mờ dần thành màu trắng và sau đó trở lại màu chính xác.

Theo tài liệu :

Để có được hiệu ứng đầy đủ của quá trình chuyển đổi, bạn phải bật chuyển tiếp nội dung cửa sổ trên cả hoạt động gọi và hoạt động được gọi. Mặt khác, hoạt động gọi sẽ bắt đầu chuyển đổi thoát, nhưng sau đó bạn sẽ thấy một chuyển đổi cửa sổ (như tỷ lệ hoặc mờ dần)

Tôi đang sử dụng getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);trên cả các hoạt động gọi và gọi.

Tương tự, nếu tôi thay đổi chuyển đổi enter thành một slide, cả hai thanh trạng thái và thanh điều hướng đều có một chuyển đổi slide với nền trắng.

Làm cách nào để ngăn thanh trạng thái và thanh điều hướng hoạt hình trong khi chuyển cảnh hoạt hình cảnh hoạt động?

Câu trả lời:


217

Có hai cách tiếp cận bạn có thể sử dụng mà tôi biết để ngăn thanh điều hướng / trạng thái hoạt hình trong quá trình chuyển đổi:

Cách tiếp cận # 1: Loại trừ thanh trạng thái và thanh điều hướng khỏi quá trình thoát / nhập mặc định của cửa sổ

Lý do tại sao thanh điều hướng / trạng thái mờ dần trong và ngoài trong quá trình chuyển đổi là vì theo mặc định, tất cả các chế độ xem không chia sẻ (bao gồm cả nền của thanh điều hướng / trạng thái) sẽ mờ dần / trong các hoạt động gọi / được gọi của bạn tương ứng khi quá trình chuyển đổi bắt đầu . Tuy nhiên, bạn có thể dễ dàng khắc phục điều này bằng cách loại trừ hình nền của thanh điều hướng / trạng thái khỏi quá trình thoát / nhập mặc định của cửa sổ Fade. Chỉ cần thêm mã sau vào onCreate()phương thức Hoạt động của bạn :

Transition fade = new Fade();
fade.excludeTarget(android.R.id.statusBarBackground, true);
fade.excludeTarget(android.R.id.navigationBarBackground, true);
getWindow().setExitTransition(fade);
getWindow().setEnterTransition(fade);

Quá trình chuyển đổi này cũng có thể được khai báo trong chủ đề của hoạt động bằng cách sử dụng XML (tức là trong res/transition/window_fade.xmltệp của riêng bạn ):

<?xml version="1.0" encoding="utf-8"?>
<fade xmlns:android="http://schemas.android.com/apk/res/android">
    <targets>
        <target android:excludeId="@android:id/statusBarBackground"/>
        <target android:excludeId="@android:id/navigationBarBackground"/>
    </targets>
</fade>

Cách tiếp cận # 2: Thêm thanh trạng thái và thanh điều hướng làm thành phần được chia sẻ

Cách tiếp cận này dựa trên câu trả lời của klmprt, gần như hiệu quả với tôi ... mặc dù tôi vẫn cần phải thực hiện một vài sửa đổi.

Trong hoạt động gọi điện của mình, tôi đã sử dụng đoạn mã sau để bắt đầu Hoạt động:

View statusBar = findViewById(android.R.id.statusBarBackground);
View navigationBar = findViewById(android.R.id.navigationBarBackground);

List<Pair<View, String>> pairs = new ArrayList<>();
if (statusBar != null) {
  pairs.add(Pair.create(statusBar, Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME));
}
if (navigationBar != null) {
  pairs.add(Pair.create(navigationBar, Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME));
}
pairs.add(Pair.create(mSharedElement, mSharedElement.getTransitionName()));

Bundle options = ActivityOptions.makeSceneTransitionAnimation(activity, 
        pairs.toArray(new Pair[pairs.size()])).toBundle();
startActivity(new Intent(context, NextActivity.class), options);

Cho đến nay, điều này về cơ bản là điều tương tự mà klmprt đề xuất trong câu trả lời của ông. Tuy nhiên, tôi cũng cần thêm đoạn mã sau vào onCreate()phương thức Hoạt động được gọi của mình để ngăn thanh trạng thái và thanh điều hướng khỏi "nhấp nháy" trong quá trình chuyển đổi:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_next);

    // Postpone the transition until the window's decor view has
    // finished its layout.
    postponeEnterTransition();

    final View decor = getWindow().getDecorView();
    decor.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            decor.getViewTreeObserver().removeOnPreDrawListener(this);
            startPostponedEnterTransition();
            return true;
        }
    });
}

Thêm hình nền của thanh trạng thái và thanh điều hướng làm các thành phần được chia sẻ sẽ buộc chúng được vẽ trên đầu chuyển đổi thoát / nhập mặc định của cửa sổ, nghĩa là chúng sẽ không mờ dần trong quá trình chuyển đổi. Thảo luận thêm về phương pháp này có thể được tìm thấy trong bài đăng trên Google+ này .


14
Bất kỳ ý tưởng tại sao findViewById (android.R.id.navlationBarBackground) sẽ trả về null trên Lollipop? Tôi đang sử dụng appcompat-v7
radzio

3
Cách tiếp cận số 2 hoạt động, nhưng vẫn còn nhấp nháy (trong hoạt động) khi quá trình chuyển đổi xảy ra. thanh trạng thái và thanh điều hướng không flickr nữa.
Akshat

16
@alex Điều này hoạt động gần như hoàn hảo đối với tôi cho đến khi chúng tôi chuyển sang thư viện hỗ trợ mới với android.support.design.widget.TabLayoutandroid.support.design.widget.AppBarLayout - bây giờ thì nhấp nháy đã trở lại
Noa Drach

6
android.R.id.navlationBarBackground có thể cung cấp cho bạn một NPE trên các thiết bị Samsung hoặc HTC vì chúng không có thanh điều hướng trên màn hình. Thực hiện kiểm tra null trước khi thêm chúng dưới dạng các yếu tố được chia sẻ
Boy

8
Tôi đang thử giải pháp này trên nexus 6 với android nougat. Nhưng cả hai cách tiếp cận đều không hiệu quả với tôi.
Pardeep Kr

4

Ngăn chặn hoàn toàn các chuyển đổi Hoạt động can thiệp vào các chuyển tiếp phần tử được chia sẻ:

Trên hoạt động thoát, hãy gọi getWindow (). SetExitTransition (null);

Về hoạt động nhập, hãy gọi getWindow (). Set EntryTransition (null);

Từ https://stackoverflow.com/a/34907685/967131

Tôi nghi ngờ điều này có thể có tác dụng phụ, nhưng không biết chắc chắn. Nó đã chết đơn giản và làm việc mặc dù.

Ngăn chặn các yếu tố cụ thể từ nhấp nháy:

Tôi bắt đầu với câu trả lời của Alex Lockwood và đã thực hiện một chút thử nghiệm để cố gắng làm cho nó hoạt động. Cốt lõi của nó là chính xác, mặc dù tôi không cần mã mà anh ấy gợi ý cho Hoạt động nhận, nhưng tôi gặp phải một số vấn đề bằng cách gọi nó trong Đoạn (thay vì Hoạt động) và bằng cách đặt thanh công cụ làm thanh hành động.

Ồ, mảnh vỡ? Tôi thấy rất nhiều ý kiến ​​cho rằng cố gắng truy xuất các tham chiếu đến thanh trạng thái và thanh điều hướng là null. Điều tương tự cũng xảy ra với tôi, cho đến khi tôi nhận ra tôi sẽ không tìm thấy những thứ đó trong bố cục của Mảnh vỡ ... chúng ở trên mức đó. Do đó, mã bên dưới để có được chế độ xem trang trí từ Hoạt động và tìm kiếm đó. Sau đó, tôi tìm thấy chúng không có vấn đề.

Cuối cùng, tôi đã phát triển phương pháp tiện ích này:

public static Bundle transitionOptions(Activity activity, int transitionViewResId, int transitionNameResId) {
   if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
       return null;
   }

   View decorView = activity.getWindow().getDecorView();
   View statusBar = decorView.findViewById(android.R.id.statusBarBackground);
   View navigationBar = decorView.findViewById(android.R.id.navigationBarBackground);
   View appBarLayout = decorView.findViewById(**R.id.appbarlayout**);
   View transitionView = decorView.findViewById(transitionViewResId);
   String transitionName = activity.getString(transitionNameResId);

   List<Pair<View, String>> pairs = new ArrayList<>();
   pairs.add(Pair.create(statusBar, Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME));
   pairs.add(Pair.create(navigationBar, Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME));
   if (appBarLayout != null) {
       pairs.add(Pair.create(appBarLayout, activity.getString(**R.string.transition_appbarlayout**)));
   }
   pairs.add(Pair.create(transitionView, transitionName));
   //noinspection unchecked - we're not worried about the "unchecked" conversion of List<Pair> to Pair[] here
   return ActivityOptionsCompat.makeSceneTransitionAnimation(activity, pairs.toArray(new Pair[pairs.size()]))
           .toBundle();
}

Lưu ý R.string.transition_appbarlayoutR.id.appbarlayout . Các ID này là tùy ý, miễn là chúng khớp với những gì mã của bạn sử dụng. Trong XML của tôi, tôi bố trí thanh hành động tùy chỉnh như vậy (được chỉnh sửa thành các yếu tố cần thiết):

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
    android:id="**@+id/appbarlayout**"
    android:transitionName="**@string/transition_appbarlayout**">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"/>
</android.support.design.widget.AppBarLayout>

Nếu bạn không sử dụng Thanh công cụ như thế này, phần đó có thể bị xóa khỏi phương thức tiện ích.

Sau đó, bạn sẽ gọi nó trong Fragment của bạn như vậy:

startActivity(intent, UIUtils.transitionOptions(getActivity(),
                        R.id.**my_view**,
                        R.string.**transition_my_view**));

Sử dụng bất kỳ giá trị nào bạn muốn, miễn là nó phù hợp với XML của bạn.

Điều này ngăn thanh trạng thái, thanh công cụ và thanh điều hướng (nút quay lại / nhà / ứng dụng gần đây) không nhấp nháy trong quá trình chuyển đổi. Phần còn lại của quá trình chuyển đổi Activity là bình thường.

Trong trường hợp của tôi, chủ đề ứng dụng của chúng tôi có một android:windowBackgroundmàu xanh. Điều này gây ra một đèn flash màu xanh trong quá trình chuyển đổi, khá khó chịu. Nhưng thay vì thực hiện một thay đổi ảnh hưởng đến toàn bộ ứng dụng như vậy, bây giờ tôi sẽ sử dụng tùy chọn đầu tiên, nhanh chóng và bẩn thỉu.


3

Bạn cần chia sẻ chúng trong ActivityOptions.makeSceneTransitionAnimation.

Ví dụ:

ActivityOptions.makeSceneTransitionAnimation(... Pair.create(activity.findViewById(android.R.id.window_status_bar), Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME) 

(xin lỗi psuedo; tôi không có giá trị android.R.id chính xác trong tay)

Bạn có thể chạy một chuyển tiếp thích hợp sau khi đã chia sẻ quan điểm.


Điều này có làm việc cho bạn? Tôi đã thử điều này và thanh trạng thái và thanh điều hướng vẫn nhấp nháy màu trắng trong quá trình chuyển đổi.
rlay3

Vâng, nó làm việc cho tôi. Bạn có chắc chắn không có chế độ xem nào khác có thể chồng lấp chúng tạm thời không? Bạn đã thử thiết lập một chuyển đổi hoạt động đơn giản trong môi trường 'hộp cát' để cô lập vấn đề chưa?
klmprt

@klmprt Tôi nghĩ rằng bạn cũng cần hoãn quá trình chuyển đổi để làm cho nó hoạt động ... Tôi cũng không thể ngăn các thanh trạng thái / điều hướng hoạt hình chỉ bằng cách chia sẻ các chế độ xem. Tôi đoán bạn cần đợi chế độ xem trang trí của cửa sổ để hoàn tất bố cục của nó trước khi bạn bắt đầu quá trình chuyển đổi bắt đầu.
Alex Lockwood

@klmprt Câu trả lời của tôi vẫn không giải quyết được là cách ngăn màu nền của Action Bar hoạt hình trong quá trình chuyển đổi. Nếu cả hai Hoạt động chia sẻ cùng màu nền của Thanh hành động, thì màu nền của thanh hành động sẽ xuất hiện để tạo hiệu ứng khi thanh hành động của Hoạt động gọi dần dần biến mất và thanh hành động được gọi là Hoạt động nhẹ nhàng mờ dần. Bạn có biết cách khắc phục điều này không vấn đề?
Alex Lockwood

@klmprt Thật ra, tôi nghĩ có một giải pháp thậm chí còn tốt hơn. Bạn chỉ có thể loại trừ các nền của thanh điều hướng / trạng thái làm các mục tiêu trong quá trình thoát / nhập mặc định của cửa sổ. Xem câu trả lời cập nhật của tôi để biết chi tiết.
Alex Lockwood

3

Theo tôi hiểu điều này là do sự chồng chéo hoạt động. Để khắc phục vấn đề này, tôi đã sử dụng các giá trị sau trong các onCreate()phương thức của cả hai hoạt động:

getWindow().setAllowEnterTransitionOverlap(false);
getWindow().setAllowReturnTransitionOverlap(false);

3

Tôi chỉ có vấn đề tương tự, và các câu trả lời dường như thiếu một phần quan trọng cho câu đố. Hãy nhớ rằng trong quá trình chuyển đổi thành phần được chia sẻ, mọi thứ xảy ra trong Hoạt động đích .

Để xóa hiệu ứng nhấp nháy, chỉ cần thêm các mục sau vào hoạt động được gọi:

Fade fade = new Fade();
fade.excludeTarget(android.R.id.statusBarBackground, true);
fade.excludeTarget(android.R.id.navigationBarBackground, true);

getWindow().setEnterTransition(fade);
getWindow().setExitTransition(fade);

Điều này sẽ giải quyết vấn đề của bạn!


Chào. Đây có phải giống như Cách tiếp cận số 1 trong câu trả lời hàng đầu không?
rlay3

@ rlay3 Không hoàn toàn. Theo như tôi có thể nói, anh ta không bao giờ đề cập đến thực tế rằng điều này chỉ cần được đặt trong hoạt động đích.
LukeWaggoner

hey @LukeWaggoner bạn có thể giúp tôi điều này: stackoverflow.com/questions/50189286/...
Blackhawk

Bạn phải loại trừ thanh trạng thái và thanh điều hướng trong cả hoạt động, người gọi và người được gọi.
Giovanni Di Gregorio

1

getWindow().setEnterTransition(null); trên quá trình chuyển đổi Entering đã loại bỏ lớp phủ màu trắng cho tôi.


0

Đây là cách tôi đã làm nó. Tôi chia sẻ cả Status BarNavigation Bartrong SharedElementTransitioncùng với một ImageView:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  View imageView = view.findViewById(R.id.iv);
  Resources resources = view.getResources();
  imageView.setTransitionName(resources.getString(R.string.transition_image_thumbnail));

  Pair<View, String> p1 = Pair.create(imageView, resources.getString(R.string.transition_image_thumbnail));

  Window window = getActivity().getWindow();

  View navigationBar = getActivity().findViewById(android.R.id.navigationBarBackground);
  View statusBar = getActivity().findViewById(android.R.id.statusBarBackground);

  Pair<View, String> p2 = Pair.create(statusBar, statusBar.getTransitionName());
  Pair<View, String> p3 = Pair.create(navigationBar, navigationBar.getTransitionName());

  ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(),
          p1, p2, p3);

  ActivityCompat.startActivity(getActivity(), intent, options.toBundle());
} else {
  startActivity(intent);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.