Hiển thị DialogFragment với hoạt ảnh phát triển từ một điểm


93

Tôi đang hiển thị một DialogFragmentkhi người dùng chạm vào một hàng trong một ListView. Tôi muốn tạo hoạt ảnh cho việc hiển thị hộp thoại để nó phát triển từ giữa hàng. Hiệu ứng tương tự có thể được nhìn thấy khi mở một thư mục từ trình khởi chạy.

Một ý tưởng mà tôi đã có là sự kết hợp của TranslateAnimationScaleAnimation. Có cách nào khác không?


1
Tham khảo liên kết cho các hình ảnh động trên DialogFragment.
ASH

Câu trả lời:


168

DialogFragmentmột trình bao bọc cho Dialoglớp học, bạn nên đặt một chủ đề cho cơ sở của mình Dialogđể có được hoạt ảnh bạn muốn:

public class CustomDialogFragment extends DialogFragment implements OnEditorActionListener
{
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) 
    {
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) 
    {
        // Set a theme on the dialog builder constructor!
        AlertDialog.Builder builder = 
            new AlertDialog.Builder( getActivity(), R.style.MyCustomTheme );

        builder  
        .setTitle( "Your title" )
        .setMessage( "Your message" )
        .setPositiveButton( "OK" , new DialogInterface.OnClickListener() 
            {      
              @Override
              public void onClick(DialogInterface dialog, int which) {
              dismiss();                  
            }
        });
        return builder.create();
    }
}

Sau đó, bạn chỉ cần xác định chủ đề sẽ bao gồm hoạt ảnh mong muốn của bạn. Trong styles.xml, thêm chủ đề tùy chỉnh của bạn:

<style name="MyCustomTheme" parent="@android:style/Theme.Panel">
    <item name="android:windowAnimationStyle">@style/MyAnimation.Window</item>
</style>

<style name="MyAnimation.Window" parent="@android:style/Animation.Activity"> 
    <item name="android:windowEnterAnimation">@anim/anim_in</item>
    <item name="android:windowExitAnimation">@anim/anim_out</item>
</style>    

Bây giờ thêm các tệp hoạt ảnh trong thư mục res / anim :

(chính android:pivotYlà chìa khóa)

anim_in.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:interpolator="@android:anim/linear_interpolator"
        android:fromXScale="0.0"
        android:toXScale="1.0"
        android:fromYScale="0.0"
        android:toYScale="1.0"
        android:fillAfter="false"
        android:startOffset="200"
        android:duration="200" 
        android:pivotX = "50%"
        android:pivotY = "-90%"
    />
    <translate
        android:fromYDelta="50%"
        android:toYDelta="0"
        android:startOffset="200"
        android:duration="200"
    />
</set>

anim_out.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:interpolator="@android:anim/linear_interpolator"
        android:fromXScale="1.0"
        android:toXScale="0.0"
        android:fromYScale="1.0"
        android:toYScale="0.0"
        android:fillAfter="false"
        android:duration="200" 
        android:pivotX = "50%"        
        android:pivotY = "-90%"        
    />
    <translate
        android:fromYDelta="0"
        android:toYDelta="50%"
        android:duration="200"
    />
</set>

Cuối cùng, điều khó khăn ở đây là làm cho hoạt ảnh của bạn phát triển từ trung tâm của mỗi hàng. Tôi cho rằng hàng đang lấp đầy màn hình theo chiều ngang, vì vậy, một mặt android:pivotXgiá trị sẽ là tĩnh. Mặt khác, bạn không thể sửa đổi android:pivotYgiá trị theo chương trình.

Những gì tôi đề xuất là, bạn xác định một số hoạt ảnh, mỗi hoạt ảnh có một giá trị phần trăm khác nhau trên android:pivotYthuộc tính (và một số chủ đề tham chiếu đến các hoạt ảnh đó). Sau đó, khi người dùng nhấn vào hàng, hãy tính vị trí Y theo phần trăm của hàng trên màn hình. Biết vị trí theo tỷ lệ phần trăm, hãy gán chủ đề có android:pivotYgiá trị thích hợp cho hộp thoại của bạn .

Nó không phải là một giải pháp hoàn hảo nhưng có thể giúp bạn. Nếu bạn không thích kết quả, thì tôi khuyên bạn nên bỏ qua DialogFragmentvà tạo hoạt ảnh cho một Viewsự phát triển đơn giản từ chính giữa hàng.

Chúc may mắn!


Ý tưởng hay với nhiều hoạt ảnh cho các vị trí khác nhau trên màn hình. Đó là một cuộc tấn công, nhưng nó dường như là cách duy nhất.
Edward Dale

Điều này sẽ chỉ xảy ra với> API 11 @Kiran Babu câu trả lời là một công việc xung quanh
Blundell

Bạn có biết liệu có cách nào khả thi để nhận được cuộc gọi lại khi những hoạt ảnh này hoàn thành không? Tôi muốn thực hiện hoạt ảnh gồm 2 phần, một phần trong đó hộp thoại trình chiếu và sau đó làm mờ các chế độ xem trong đó. Làm cách nào để đính kèm một người nghe vào windowAnimations?
android_student

Xuất sắc! Đó là điều mà tôi đã tìm kiếm!
Aleksey Timoshchenko

2
Thiết theme có thể đơn giản như làm setStyle(DialogFragment.STYLE_NORMAL, R.style.MyCustomTheme)trên onCreate(bundle)Xem: developer.android.com/reference/android/app/DialogFragment.html
cá nhiệt đới

117

Kiểm tra nó xem mã này, nó phù hợp với tôi

// Trượt lên hoạt ảnh

<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromYDelta="100%"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toXDelta="0" />

</set>

// Trượt ảnh động dowm

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromYDelta="0%p"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toYDelta="100%p" />

</set>

// Phong cách

<style name="DialogAnimation">
    <item name="android:windowEnterAnimation">@anim/slide_up</item>
    <item name="android:windowExitAnimation">@anim/slide_down</item>
</style>

// Phân đoạn hộp thoại bên trong

@Override
public void onActivityCreated(Bundle arg0) {
    super.onActivityCreated(arg0);
    getDialog().getWindow()
    .getAttributes().windowAnimations = R.style.DialogAnimation;
}

8
Xin lỗi, điều này không trả lời câu hỏi của tôi.
Edward Dale

3
Đây có thể không phải là chính xác những gì OP đang yêu cầu, nhưng đó là một điểm vào tốt, tôi nghĩ.
mdelolmo

2
Ví dụ xuất sắc! Mẫu duy nhất phù hợp với tôi. Thủ thuật là đặt hoạt ảnh / chủ đề trong phương thức onActivityCreate (...)
tomurka

3
Điều này có thể hữu ích nhưng nó không trả lời câu hỏi nào cả.
Olayinka

Bạn có biết liệu có cách nào khả thi để nhận được cuộc gọi lại khi những hoạt ảnh này hoàn thành không? Tôi muốn thực hiện hoạt ảnh gồm 2 phần, một phần trong đó hộp thoại trình chiếu và sau đó làm mờ các chế độ xem trong đó. Làm cách nào để đính kèm một người nghe vào windowAnimations?
android_student

22

DialogFragment có một phương thức getTheme () công khai mà bạn có thể vượt qua vì lý do chính xác này. Giải pháp này sử dụng ít dòng mã hơn:

public class MyCustomDialogFragment extends DialogFragment{
    ...
    @Override
    public int getTheme() {
        return R.style.MyThemeWithCustomAnimation;
    }
}

1
Không còn lo lắng ... Giải pháp đơn giản và dễ hiểu.
Noundla Sandeep

Đây là câu trả lời tốt nhất cho tôi!
superuser

Mặc dù không liên quan đến câu hỏi ban đầu, tôi đã có một thư viện hiển thị trong MainAcitvity nơi người dùng nhấp vào sẽ kích hoạt trình chiếu trong DialogFragment. Tuy nhiên, có hiện tượng giật trong MainActivity bất cứ khi nào quay lại từ trình chiếu. Điều này là do MainActivity sử dụng AppTheme.NoActionBartrong khi DialogFragment đang sử dụng mặc định AppTheme. Phương pháp trên đã giải quyết vấn đề của tôi bằng cách có chủ đề nhất quán trong cả phân đoạn và hoạt động.
tingyik90

Bro, bạn là thiên tài
Jacky Chong

Giải pháp này đã làm việc cho tôi. Tuy nhiên có một điều khiến tôi bối rối; cài đặt windowEnterAnimation hoặc windowExitAnimation trực tiếp trong Chủ đề sẽ không tạo ra sự khác biệt trong các hoạt ảnh DialogFragment của tôi. Điều duy nhất hiệu quả với tôi là đặt windowAnimationStyle thành một tệp XML riêng biệt xác định kiểu và đặt các hoạt ảnh vào và ra ở đó
szaske

9

Để có hộp thoại toàn màn hình với hoạt ảnh, hãy viết như sau ...

Kiểu dáng:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="actionModeBackground">?attr/colorPrimary</item>
    <item name="windowActionModeOverlay">true</item>
</style>

<style name="AppTheme.NoActionBar">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
</style>

<style name="AppTheme.NoActionBar.FullScreenDialog">
    <item name="android:windowAnimationStyle">@style/Animation.WindowSlideUpDown</item>
</style>

<style name="Animation.WindowSlideUpDown" parent="@android:style/Animation.Activity">
    <item name="android:windowEnterAnimation">@anim/slide_up</item>
    <item name="android:windowExitAnimation">@anim/slide_down</item>
</style>

res / anim / slide_up.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="@android:interpolator/accelerate_quad">

    <translate
        android:duration="@android:integer/config_shortAnimTime"
        android:fromYDelta="100%"
        android:toYDelta="0%"/>
</set>

res / anim / slide_down.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="@android:interpolator/accelerate_quad">

    <translate
        android:duration="@android:integer/config_shortAnimTime"
        android:fromYDelta="0%"
        android:toYDelta="100%"/>
</set>

Mã Java:

public class MyDialog extends DialogFragment {

    @Override
    public int getTheme() {
        return R.style.AppTheme_NoActionBar_FullScreenDialog;
    }
}

private void showDialog() {
    FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
    Fragment previous = getSupportFragmentManager().findFragmentByTag(MyDialog.class.getName());
    if (previous != null) {
        fragmentTransaction.remove(previous);
    }
    fragmentTransaction.addToBackStack(null);

    MyDialog dialog = new MyDialog();
    dialog.show(fragmentTransaction, MyDialog.class.getName());
}

4

Sử dụng chế độ xem trang trí bên trong OnStart trong đoạn hộp thoại của bạn

@Override
public void onStart() {
    super.onStart();


    final View decorView = getDialog()
            .getWindow()
            .getDecorView();

    decorView.animate().translationY(-100)
            .setStartDelay(300)
            .setDuration(300)
            .start();

}

1
Quan điểm cơ bản dường như không được nhấp sau đó
HaydenKai

3

Trong DialogFragment, hoạt ảnh tùy chỉnh được gọi là onCreateDialog. 'DialogAnimation' là kiểu hoạt ảnh tùy chỉnh trong câu trả lời trước.

public Dialog onCreateDialog(Bundle savedInstanceState) 
{
    final Dialog dialog = super.onCreateDialog(savedInstanceState);
    dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
    return dialog;
}

1

Bạn đã xem phần Đào tạo dành cho nhà phát triển Android về cách phóng to chế độ xem chưa? Có thể là một điểm khởi đầu tốt.

Bạn có thể muốn tạo một lớp tùy chỉnh mở rộng DialogFragmentđể làm việc này.

Ngoài ra, hãy xem Jake Whartons NineOldAndroids về khả năng tương thích API của Honeycomb Animation trong suốt quá trình quay trở lại API Cấp 1.


1

Nếu bạn muốn làm việc trên các API, bạn phải thực hiện bên trong DialogFragemnt-> onStart chứ không phải bên trong onCreateDialog

@Override
    public void onStart() 
    {
        if (getDialog() == null) 
        {
            return;
        }

        getDialog().getWindow().setWindowAnimations(
                  R.style.DlgAnimation);

        super.onStart();
    }

Giải pháp tốt nhất theo ý kiến ​​của tôi. Nó cũng hoạt động cho AlertDialogs, chỉ cần sử dụng nó trong onShowListener. Cảm ơn!
Gabor Novak

0

Thêm mã này vào hoạt ảnh giá trị

 <scale
    android:duration="@android:integer/config_longAnimTime"
    android:fromXScale="0.2"
    android:fromYScale="0.2"
    android:toXScale="1.0"
    android:toYScale="1.0"
    android:pivotX="50%"
    android:pivotY="50%"/>
<alpha
    android:fromAlpha="0.1"
    android:toAlpha="1.0"
    android:duration="@android:integer/config_longAnimTime"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"/>

gọi trên styles.xml

<style name="DialogScale">
    <item name="android:windowEnterAnimation">@anim/scale_in</item>
    <item name="android:windowExitAnimation">@anim/scale_out</item>
</style>

Trên mã java: đặt Onclick

public void onClick(View v) {
        fab_onclick(R.style.DialogScale, "Scale" ,(Activity) context,getWindow().getDecorView().getRootView());
      //  Dialogs.fab_onclick(R.style.DialogScale, "Scale");

    }

thiết lập trên phương pháp:

alertDialog.getWindow().getAttributes().windowAnimations = type;
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.