আমি কীভাবে ডায়ালগগুলিতে ইমারসিভ মোড বজায় রাখতে পারি?


104

যখন আমার ক্রিয়াকলাপগুলি একটি কাস্টম ডায়ালগ প্রদর্শন করে তবে আমি নতুন ইমারসিভ মোডটি কীভাবে বজায় রাখব?

আমি ডায়ালগগুলিতে ইমারসিভ মোডটি বজায় রাখতে নীচের কোডটি ব্যবহার করছি, তবে সেই সমাধানের সাথে, আমি আমার কাস্টম ডায়ালগ শুরু করলে নাভবারটি এক সেকেন্ডেরও কম সময়ের জন্য উপস্থিত হয়, তবে এটি অদৃশ্য হয়ে যায়।

নিম্নলিখিত ভিডিওটি ইস্যুটিকে আরও ভালভাবে ব্যাখ্যা করেছে (ন্যাবারটি প্রদর্শিত হলে পর্দার নীচে দেখুন): http://youtu.be/epnd5ghey8g

আমি কীভাবে এই আচরণটি এড়াতে পারি?

কোড

আমার আবেদনে সমস্ত ক্রিয়াকলাপের জনক:

public abstract class ImmersiveActivity extends Activity {

    @SuppressLint("NewApi")
    private void disableImmersiveMode() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
            getWindow().getDecorView().setSystemUiVisibility(
                    View.SYSTEM_UI_FLAG_FULLSCREEN
            );
        }
    }

    @SuppressLint("NewApi")
    private void enableImmersiveMode() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
            getWindow().getDecorView().setSystemUiVisibility(
                      View.SYSTEM_UI_FLAG_LAYOUT_STABLE 
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 
                    | View.SYSTEM_UI_FLAG_FULLSCREEN 
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            );
        }
    }


    /**
     * Set the Immersive mode or not according to its state in the settings:
     * enabled or not.
     */
    protected void updateSystemUiVisibility() {
        // Retrieve if the Immersive mode is enabled or not.
        boolean enabled = getSharedPreferences(Util.PREF_NAME, 0).getBoolean(
                "immersive_mode_enabled", true);

        if (enabled) enableImmersiveMode();
        else disableImmersiveMode();
    }

    @Override
    public void onResume() {
        super.onResume();
        updateSystemUiVisibility();
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        updateSystemUiVisibility();
    }

}


আমার সমস্ত কাস্টম ডায়ালগগুলি তাদের onCreate(. . .)পদ্ধতিতে এই পদ্ধতিটিকে কল করে :

/**
 * Copy the visibility of the Activity that has started the dialog {@link mActivity}. If the
 * activity is in Immersive mode the dialog will be in Immersive mode too and vice versa.
 */
@SuppressLint("NewApi")
private void copySystemUiVisibility() {
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
        getWindow().getDecorView().setSystemUiVisibility(
                mActivity.getWindow().getDecorView().getSystemUiVisibility()
        );
    }
}


সম্পাদনা করুন - সমাধান (Beaver6813 ধন্যবাদ, আরও তথ্যের জন্য তার উত্তর দেখুন):

আমার সমস্ত কাস্টম সংলাপগুলি শো পদ্ধতিটিকে এইভাবে ওভাররাইড করে:

/**
 * An hack used to show the dialogs in Immersive Mode (that is with the NavBar hidden). To
 * obtain this, the method makes the dialog not focusable before showing it, change the UI
 * visibility of the window like the owner activity of the dialog and then (after showing it)
 * makes the dialog focusable again.
 */
@Override
public void show() {
    // Set the dialog to not focusable.
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);

    copySystemUiVisibility();

    // Show the dialog with NavBar hidden.
    super.show();

    // Set the dialog to focusable again.
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
}

কীভাবে ডায়লগ দেখায়? আপনি কি ডায়ালগফ্রেগমেন্টগুলি ব্যবহার করেন?
টাদিয়াস ক্রিজ

আমি ডায়ালগফ্রেগমেন্টগুলি ব্যবহার করি না তবে কাস্টম ডায়ালগ সাবক্লাসগুলি। developer.android.com/references/android/app/Dialog.html আমি ডায়ালগগুলি কেবল তাদের শো () পদ্ধতিতে কল করে দেখি।
ভ্যানডির

উইন্ডো ফোকাস চেঞ্জযুক্ত ডায়ালগটি প্রদর্শিত হলে কল করা হচ্ছে। সংলাপটি উপস্থিত হওয়ার পরে সক্ষম হওয়ার মান কী? এটি সত্য নাকি ভুল কিছু হয়েছে এবং এটি মিথ্যা?
কেভিন ভ্যান মিয়ার্লো

আপনি কী ডায়ালগ ক্লাসের (এবং ক্রিয়াকলাপ শ্রেণীর নয়) উইন্ডো ফোকাস চ্যাঞ্জড (বুলিয়ান হ্যাশ ফোকাস) পদ্ধতিটি বোঝাতে চান? এই ক্ষেত্রে "হেসফোকস" পতাকাটি সত্য।
ভ্যানডির

5
কেউ কি ডায়ালগফ্রেগমেন্ট সহ নিমজ্জন মোড ব্যবহার করেছেন?
gbero

উত্তর:


167

ইস্যুটি নিয়ে অনেক গবেষণার পরেও এর একটি হ্যাকি ফিক্স রয়েছে, যা ডায়ালগ শ্রেণিটি ছড়িয়ে দেওয়ার জন্য ছড়িয়ে পড়ে । ডায়ালগ উইন্ডোটি উইন্ডো ম্যানেজারে যুক্ত করার পরে নেভিগেশন বারটি প্রদর্শিত হয় আপনি ম্যানেজারে যোগ করার আগে ইউআই দৃশ্যমানতা সেট করে থাকলেও। ইন অ্যান্ড্রয়েড ইমারসিভ উদাহরণ এটা যে মন্তব্য করেছে আছে:

// * Uses semi-transparent bars for the nav and status bars
// * This UI flag will *not* be cleared when the user interacts with the UI.
// When the user swipes, the bars will temporarily appear for a few seconds and then
// disappear again.

আমি বিশ্বাস করি যে আমরা এখানে যা দেখছি (এটি একটি ব্যবহারকারী-ইন্টারঅ্যাকশন ট্রিগার করা হচ্ছে যখন ম্যানেজারে একটি নতুন, ফোকাসযোগ্য, উইন্ডো ভিউ যুক্ত করা হয়)।

আমরা কীভাবে এটিকে ঘিরে কাজ করতে পারি? ডায়ালগটি তৈরি করার সময় অ-ফোকাসযোগ্য করে তুলুন (যাতে আমরা কোনও ব্যবহারকারী-ইন্টারঅ্যাকশনটি ট্রিগার করি না) এবং তারপরে এটি প্রদর্শিত হওয়ার পরে এটি ফোকাসযোগ্য করে তুলি।

//Here's the magic..
//Set the dialog to not focusable (makes navigation ignore us adding the window)
dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);

//Show the dialog!
dialog.show();

//Set the dialog to immersive
dialog.getWindow().getDecorView().setSystemUiVisibility(
context.getWindow().getDecorView().getSystemUiVisibility());

//Clear the not focusable flag from the window
dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);

স্পষ্টতই এটি আদর্শ নয় তবে এটি একটি অ্যান্ড্রয়েড বাগ বলে মনে হচ্ছে, উইন্ডোটিতে নিমজ্জন সেট রয়েছে কিনা তা তাদের পরীক্ষা করা উচিত।

আমি আমার কাজের পরীক্ষা কোড (হল hacky messiness ক্ষমা) এর আপডেট করেছি গিটহাব । আমি Nexus 5 এমুলেটর পরীক্ষা করেছি, এটি সম্ভবত KitKat এর চেয়ে কম কিছু দিয়ে ফুটিয়ে তুলবে তবে এটি কেবল প্রমাণ-ধারণার জন্য।


3
নমুনা প্রকল্পের জন্য ধন্যবাদ তবে এটি কার্যকর হয়নি। আমার নেক্সাস 5 এ যা ঘটে দেখুন: youtu.be/-abj3V_0zcU
ভ্যানডির

আমি বিষয়টি সম্পর্কে কিছু তদন্তের পরে আমার উত্তর আপডেট করেছি, এটি ছিল শক্ত! একটি নেক্সাস 5 এমুলেটর পরীক্ষিত, আশা করি এটি কাজ করে।
Beaver6813

2
আমি পেয়েছি 'অনুরোধ ফিচার () অবশ্যই সামগ্রী যুক্ত করার আগে কল করা উচিত' (আমি মনে করি এটি ক্রিয়াকলাপে সক্রিয় বৈশিষ্ট্যের উপর নির্ভর করে)। সমাধান: ডায়ালগটি সরান sh (এক) লাইন উপরে দেখান যাতে সিস্টেমউইভিজবিলিটি অনুলিপি করার আগে (তবে মনোনিবেশযোগ্য না সেট করার পরে) দেখানো হয় ()। তারপরেও এটি এনএভি-বার লাফানো ছাড়াই কাজ করে।
আরবার্গ

5
@ Beaver6813 এডিটেক্সট ব্যবহার করা হয় এবং ডায়ালগফ্র্যাগমেন্টে সফটকিবোর্ড প্রদর্শিত হলে এটি কাজ করে না। এটি হ্যান্ডেল করার জন্য আপনার কাছে কোন পরামর্শ নেই।
androidcodehunter

1
হাই বিভার 6813 আমার ডায়লগে একটি সম্পাদনা পাঠ্য থাকলে এটি কার্যকর হয় না। কোন সমাধান আছে ??
নবীন গুপ্ত

33

আপনার তথ্যের জন্য @ বিভার 6813 এর উত্তরের জন্য ধন্যবাদ, আমি ডায়ালগফ্রেগমেন্টটি ব্যবহার করে এই কাজটি করতে সক্ষম হয়েছি।

আমার ডায়ালগফ্র্যাগমেন্টের অনক্রিটভিউ পদ্ধতিতে, আমি স্রেফ নিম্নলিখিতগুলি যুক্ত করেছি:

    getDialog().getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
    getDialog().getWindow().getDecorView().setSystemUiVisibility(getActivity().getWindow().getDecorView().getSystemUiVisibility());

    getDialog().setOnShowListener(new DialogInterface.OnShowListener() {
        @Override
        public void onShow(DialogInterface dialog) {
            //Clear the not focusable flag from the window
            getDialog().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);

            //Update the WindowManager with the new attributes (no nicer way I know of to do this)..
            WindowManager wm = (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE);
            wm.updateViewLayout(getDialog().getWindow().getDecorView(), getDialog().getWindow().getAttributes());
        }
    });

5
এটি অনক্রিয়েটডায়ালগ () এ বিল্ডার প্যাটার্নটির সাথে কাজ করে? আমার ডায়ালগফ্রেগমেন্টগুলির সাথে কাজ করার জন্য আমি এখনও এই হ্যাকটি পাইনি, ডায়ালগটি "অ্যাপ্লিকেশন ফিচার () এর সাথে আমার অ্যাপ্লিকেশনটিকে ক্র্যাশ করেছে কনটেন্ট যুক্ত করার আগে অবশ্যই ডাকতে হবে"
আইএএমকেলে

1
এটি উজ্জ্বল এবং আমার ডায়ালগফ্রেগমেন্টগুলির একমাত্র সমাধান ছিল। তোমাকে অনেক ধন্যবাদ.
se22as

গ্রেট! এটি পুরোপুরি কাজ করে। অনেক কিছুই চেষ্টা করেছেন, এখন নিখুঁতভাবে নিমজ্জন মোডে চালিয়ে যান।
পিটারডকে

বাহ, একটি কবজ মত কাজ। ধন্যবাদ
আব্দুল

16

আপনি যদি ব্যবহার করতে চান অনক্রিটডায়ালগ () এই ক্লাসটি ব্যবহার করে দেখুন। এটি আমার পক্ষে বেশ ভাল কাজ করে ...

public class ImmersiveDialogFragment extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        AlertDialog alertDialog = new AlertDialog.Builder(getActivity())
                .setTitle("Example Dialog")
                .setMessage("Some text.")
                .create();

        // Temporarily set the dialogs window to not focusable to prevent the short
        // popup of the navigation bar.
        alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);

        return alertDialog;

    }

    public void showImmersive(Activity activity) {

        // Show the dialog.
        show(activity.getFragmentManager(), null);

        // It is necessary to call executePendingTransactions() on the FragmentManager
        // before hiding the navigation bar, because otherwise getWindow() would raise a
        // NullPointerException since the window was not yet created.
        getFragmentManager().executePendingTransactions();

        // Hide the navigation bar. It is important to do this after show() was called.
        // If we would do this in onCreateDialog(), we would get a requestFeature()
        // error.
        getDialog().getWindow().getDecorView().setSystemUiVisibility(
            getActivity().getWindow().getDecorView().getSystemUiVisibility()
        );

        // Make the dialogs window focusable again.
        getDialog().getWindow().clearFlags(
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        );

    }

}

কথোপকথনটি দেখাতে, আপনার ক্রিয়াকলাপে নিম্নলিখিতটি করুন ...

new ImmersiveDialogFragment().showImmersive(this);

যখন অ্যাকশনবার মেনু প্রদর্শিত হয় তখন নাভিবারটি কীভাবে থামানো যায় সে সম্পর্কে কোনও ধারণা?
উইলিয়াম

আমি এখনও এনপিই পাই, কারণ গেটডায়ালগ () বাতিল করে দেয়। কিভাবে তুমি সেটা সম্পাদন করলা?
আন্তন শকুরেঙ্কো

8

উত্তরগুলির সংমিশ্রণটি আমি একটি বিমূর্ত শ্রেণি তৈরি করেছি যা সব ক্ষেত্রেই কাজ করে:

public abstract class ImmersiveDialogFragment extends DialogFragment {

    @Override
    public void setupDialog(Dialog dialog, int style) {
        super.setupDialog(dialog, style);

        // Make the dialog non-focusable before showing it
        dialog.getWindow().setFlags(
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
    }

    @Override
    public void show(FragmentManager manager, String tag) {
        super.show(manager, tag);
        showImmersive(manager);
    }

    @Override
    public int show(FragmentTransaction transaction, String tag) {
        int result = super.show(transaction, tag);
        showImmersive(getFragmentManager());
        return result;
    }

    private void showImmersive(FragmentManager manager) {
        // It is necessary to call executePendingTransactions() on the FragmentManager
        // before hiding the navigation bar, because otherwise getWindow() would raise a
        // NullPointerException since the window was not yet created.
        manager.executePendingTransactions();

        // Copy flags from the activity, assuming it's fullscreen.
        // It is important to do this after show() was called. If we would do this in onCreateDialog(),
        // we would get a requestFeature() error.
        getDialog().getWindow().getDecorView().setSystemUiVisibility(
                getActivity().getWindow().getDecorView().getSystemUiVisibility()
        );

        // Make the dialogs window focusable again
        getDialog().getWindow().clearFlags(
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        );
    }
}

অ্যান্ড্রয়েডেক্সের পরে, সেটআপডায়ালগ পদ্ধতিটি একটি সীমাবদ্ধ এপিআই হয়ে গেছে, আমরা এটিকে এড়িয়ে যাওয়া ছাড়া কীভাবে এটি মোকাবেলা করতে পারি?
মিংকাং প্যান

5

এটি আপনার কথোপকথন খণ্ডের অন ডিসিডিস পদ্ধতিতে চালিয়ে যায়। এবং সেই পদ্ধতির মধ্যে ক্রিয়াকলাপটির পদ্ধতিটিকে কল করুন যার সাথে এটি আবার যুক্ত হয়েছে পুরো স্ক্রিনের পতাকা সেট করুন।

@Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);
        Logger.e(TAG, "onDismiss");
        Log.e("CallBack", "CallBack");
        if (getActivity() != null &&
                getActivity() instanceof LiveStreamingActivity) {
            ((YourActivity) getActivity()).hideSystemUI();
        }
    }

এবং আপনার ক্রিয়াকলাপে এই পদ্ধতিটি যুক্ত করুন:

public void hideSystemUI() {
        // Set the IMMERSIVE flag.
        // Set the content to appear under the system bars so that the content
        // doesn't resize when the system bars hide and show.
        getWindow().getDecorView().setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
                        | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
                        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    }

1
সর্বাধিক দরকারী মন্তব্য, যেহেতু এটি দুর্দান্ত কাজ করে AlertDialog.Builderএবং.setOnDismissListener()
টমশ করে

4

আপনি যে নিজস্ব ডায়ালগফ্রেগমেন্ট তৈরি করছেন তা আপনার কেবলমাত্র এই পদ্ধতিটিকে ওভাররাইড করতে হবে।

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    Dialog dialog = super.onCreateDialog(savedInstanceState);

    dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);

    return dialog;
}

আপনি ডায়ালগের অভ্যন্তরে যে কোনও কিছুতে চাপতে সক্ষম হবেন না কারণ এটি সত্যিই আদর্শ নয় :(
স্লট

এটি ব্যবহার করে আমার সংলাপগুলি প্রতিক্রিয়াহীন হয়ে ওঠে। তবে যদি আপনি জেদ করেন যে এটি কাজ করে তবে আমি এটিকে আবার যেতে দেব।
স্লট

@ স্লট আপনি WindowManager.LayoutParams.FLAG_NOT_FOCUSABLEডায়লগটি দেখানোর পরে সাফ করা দরকার
ইমোডন

2

আমি জানি এটি পুরানো পোস্ট, তবে আমার উত্তরটি অন্যকে সাহায্য করতে পারে।

ডায়ালগগুলিতে ইমারসিভ এফেক্টের হ্যাকি ঠিক করা নীচে:

public static void showImmersiveDialog(final Dialog mDialog, final Activity mActivity) {
        //Set the dialog to not focusable
        mDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
        mDialog.getWindow().getDecorView().setSystemUiVisibility(setSystemUiVisibility());

        mDialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                //Clear the not focusable flag from the window
                mDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);

                //Update the WindowManager with the new attributes
                WindowManager wm = (WindowManager) mActivity.getSystemService(Context.WINDOW_SERVICE);
                wm.updateViewLayout(mDialog.getWindow().getDecorView(), mDialog.getWindow().getAttributes());
            }
        });

        mDialog.getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                    mDialog.getWindow().getDecorView().setSystemUiVisibility(setSystemUiVisibility());
                }

            }
        });
    }

    public static int setSystemUiVisibility() {
        return View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.