ভ্যাগপ্যাজারে খণ্ড কীভাবে দৃশ্যমান হবে তা কীভাবে নির্ধারণ করবেন


754

সমস্যা: অসম্পূর্ণ অংশ onResume()মধ্যেViewPager সামনে টুকরা আসলে দৃশ্যমান হয় বহিস্কার করা হয়।

উদাহরণস্বরূপ, আমি 2 টুকরা আছে ViewPagerএবং FragmentPagerAdapter। দ্বিতীয় খণ্ডটি কেবল অনুমোদিত ব্যবহারকারীর জন্য উপলব্ধ এবং যখন খণ্ডটি দৃশ্যমান হয়ে যায় তখন আমি ব্যবহারকারীকে লগ ইন করতে বলি (সতর্কতা ডায়ালগ ব্যবহার করে)।

কিন্তু ViewPager দ্বিতীয় টুকরা তৈরি করে যখন প্রথম অর্ডার দ্বিতীয় টুকরা ক্যাশে করার জন্য দৃশ্যমান এবং যখন ব্যবহারকারী স্যুইপিং শুরু এটিকে দৃশ্যমান করে তোলে।

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

কিভাবে এই কাজ করা যেতে পারে?


18
"ভিউপ্যাজার এবং ফ্রেগমেন্টপাগারএডাপ্টারের সাথে আমার 2 টি টুকরো রয়েছে The দ্বিতীয় খণ্ডটি কেবলমাত্র অনুমোদিত ব্যবহারকারীদের জন্যই উপলব্ধ থাকতে পারে এবং খণ্ডটি দৃশ্যমান হয়ে গেলে (সতর্কতা ডায়ালগ) হয়ে গেলে আমার লগইন করার জন্য জিজ্ঞাসা করা উচিত" " - আইএমএইচও, এটি ভয়ঙ্কর ইউএক্স। একটি ডায়ালগ পপিং করা হচ্ছে কারণ ব্যবহারকারী অনুভূমিকভাবে সোয়াইপ করেছে আমাকে প্লে স্টোরটিতে আপনাকে একটি তারকা-রেটিং দেবে।
কমন্সওয়্যার

"লগইন" বোতামের সাহায্যে টেক্সটভিউতে কেবল তথ্য প্রদর্শন করা আরও ভাল? এই ক্ষেত্রে আপনার সমাধান কী?
4ntoine

5
"ডেটা প্রদর্শিত না হলে এটি লোড করার দরকার নেই" " - তাহলে আপনি এটি একটি করা উচিত হবে না ViewPager। দুই পৃষ্ঠার পেজারে, উভয় পৃষ্ঠাই আপনার পছন্দ হোক বা না হোক তাৎক্ষণিকভাবে লোড করা হবে। এর ব্যবহারকারীর অভিজ্ঞতা ViewPagerঅনুমান করা হয় যে কন্টেন্টটি সোয়াইপ করার সাথে সাথে সেখানে উপস্থিত রয়েছে, কিছুক্ষণ পরে নয়। এই কারণেই ViewPagerসেই ব্যবহারকারীর অভিজ্ঞতা নিশ্চিত করতে সহায়তা করার জন্য যা দৃশ্যমান তার আগে একটি পৃষ্ঠা সূচনা করে।
কমন্সওয়্যার

2
মনে হচ্ছে যে ViewPager নমনীয় যথেষ্ট নয় এবং এটি ক্যাশে থেকে সর্বনিম্ন setOffscreenPageLimit 1 বন্ধ করতে অনুমতি দেয় না: stackoverflow.com/questions/10073214/... । এর কোনও কারণ দেখতে পাবেন না এবং প্রত্যাশিত আচরণটি (বাধ্যতামূলক ক্যাশিংয়ের ক্ষেত্রে) খণ্ডটি দৃশ্যমান হয়ে গেলে BUT ফায়ার টুকরাটির অনারিউজ () তৈরি করা হয়।
4ntoine

1
কিছুটা দেরি হলেও একই সমস্যার মুখোমুখি কারও জন্য আপনি ফ্রেগমেন্টভিউপাগার লাইব্রেরিটি চেষ্টা করতে পারেন (আমি লেখক) যা এই সমস্যাটি নিয়ে কাজ করে এবং কয়েকটি অতিরিক্ত বৈশিষ্ট্য সরবরাহ করে। একটি নমুনার জন্য, প্রকল্পের গিটহাব পৃষ্ঠা বা এই স্ট্যাকওভারফ্লো উত্তরটি দেখুন
এস ব্রুখন্ড

উত্তর:


582

ভ্যাগপ্যাজারে খণ্ড কীভাবে দৃশ্যমান হবে তা কীভাবে নির্ধারণ করবেন

setUserVisibleHintআপনার এটিকে ওভাররাইড করে নিম্নলিখিতটি করতে পারেন Fragment:

public class MyFragment extends Fragment {
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
        }
        else {
        }
    }
}

7
আজকের অ্যান্ড্রয়েড সমর্থন লাইব্রেরি আপডেট (রেভ 11) এর জন্য, ব্যবহারকারীদের দৃশ্যমান ইঙ্গিত ইস্যুটি শেষ পর্যন্ত ঠিক করা হয়েছে। এখন ভিউপ্যাজারের জন্য ব্যবহারকারীর দৃশ্যমান ইঙ্গিতটি ব্যবহার করা নিরাপদ।
ওএসিস ফেং

58
আমি খুঁজে পেয়েছি যে সেটউজারভিজিবলহিন্ট পদ্ধতিটি অনক্রিটভিউ কল হওয়ার আগে ডাকা হয়ে যায় এবং এটি কোনও আরম্ভের ট্র্যাক করা কঠিন করে তোলে।
অ্যান্ড্রয়েডদেভ

11
@ অ্যান্ড্রয়েডদেভ আপনি যদি ইঙ্গিতটি সত্য হিসাবে আসার সময় কিছু কোড চালনা করতে চান তবে ভিউ ট্রিটি ইতিমধ্যে সূচনা isResumed()করা দরকার তবে এনপিই এড়াতে কেবল কোডের সেই ব্লকটি জড়ান। আমার জন্য ভাল কাজ করা হয়েছে।
রবি থাপলিয়াল

13
এটি কেবল হাস্যকর যে এসডিকে ডিফল্টরূপে সরবরাহ করা উচিত এমন কোনও কিছুর জন্য অনেকগুলি বিভিন্ন হ্যাক রয়েছে।
মাইক 6679

15
setUserVisibleHintএখন হ্রাস করা হয়েছে
এসআর

525

আপডেট : অ্যান্ড্রয়েড সমর্থন লাইব্রেরি (পুনরায় 11) অবশেষে ব্যবহারকারীদের দৃশ্যমান ইঙ্গিত সমস্যাটি স্থির করেছে , এখন আপনি যদি টুকরো টুকরো জন্য সমর্থন লাইব্রেরি ব্যবহার করেন, তবে আপনি গর্নের উত্তর দ্বারা বর্ণিত পরিবর্তনগুলি ক্যাপচার করতে নিরাপদে ব্যবহার getUserVisibleHint()বা ওভাররাইড setUserVisibleHint()করতে পারেন।

আপডেট 1 এখানে একটি ছোট সমস্যা রয়েছে getUserVisibleHint()। এই মানটি ডিফল্টরূপে true

// Hint provided by the app that this fragment is currently visible to the user.
boolean mUserVisibleHint = true;

সুতরাং যখন আপনি এটি setUserVisibleHint()চালানোর আগে এটি ব্যবহার করার চেষ্টা করবেন তখন কোনও সমস্যা হতে পারে । একটি workaround হিসাবে আপনি onCreateএই পদ্ধতিতে মান সেট করতে পারেন ।

public void onCreate(@Nullable Bundle savedInstanceState) {
    setUserVisibleHint(false);

পুরানো উত্তর:

বেশিরভাগ ব্যবহারের ক্ষেত্রে, ViewPagerকেবল একবারে একটি পৃষ্ঠা দেখান, তবে আপনি যদি ব্যবহার করছেন তবে প্রাক-ক্যাশেযুক্ত টুকরোটিকে "দৃশ্যমান" অবস্থায় (আসলে অদৃশ্য) FragmentStatePagerAdapterরাখতে হবেAndroid Support Library pre-r11

আমি ওভাররাইড:

public class MyFragment extends Fragment {
    @Override
    public void setMenuVisibility(final boolean visible) {
        super.setMenuVisibility(visible);
        if (visible) {
            // ...
        }
    }
   // ...
}

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


73
GetActivity () ব্যবহারে সচেতন থাকুন, প্রথম শুরুতে এটি বাতিল হবে।
ভোভকাব

10
নোট করুন যে setUserVisibleHint () সর্বদা ফ্র্যাগমেন্টপেজারএডাপ্টারে সঠিকভাবে কাজ করে।
louielouie

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

3
trueযখন onCreateOptionsMenuডাকা হবে তখন আমি getUserVisibleHint () এর জন্য পাচ্ছি , এবং যখন setUserVisibleHintডাকা হয়, মেনুটি এখনও তৈরি করা হয়নি বলে মনে হয়। অবশেষে আমি দুটি বিকল্প মেনু যুক্ত করব যখন আমি কেবলমাত্র টুকরো টুকরো থেকে মেনু চাই want এক্ষেত্রে কোন পরামর্শ?
cYrixmorten

13
setUserVisibleHintএখন হ্রাস করা হয়েছে
এসআর

143

এটি মনে onResume()করে যে স্বাভাবিক আচরণটি পুনরুদ্ধার করে restore এটি অ্যাপ্লিকেশনটি ছেড়ে যাওয়ার জন্য হোম কীটি টিপুন এবং তারপরে অ্যাপটিতে পুনরায় প্রবেশের সাথে ভাল অভিনয় করে। onResume()পরপর দু'বার বলা হয় না।

@Override
public void setUserVisibleHint(boolean visible)
{
    super.setUserVisibleHint(visible);
    if (visible && isResumed())
    {
        //Only manually call onResume if fragment is already visible
        //Otherwise allow natural fragment lifecycle to call onResume
        onResume();
    }
}

@Override
public void onResume()
{
    super.onResume();
    if (!getUserVisibleHint())
    {
        return;
    }

    //INSERT CUSTOM CODE HERE
}

4
ঠিক আমি খুঁজছেন ছিল কি. setUserVisibleHintআগে কল করার সাথে সমস্যাটি onCreateViewসমাধান setUserVisibleHintকরে এবং অ্যাপটি পটভূমিতে এবং তারপরে সম্মুখের দিকে চলে গেলে তা কল হয় না। অসাধারণ! ধন্যবাদ!
অ্যালেক্স

11
আমি মনে করি অনারুমে নিজেকে কল করা একটি খারাপ ধারণা but
কোয়ান্টিন জি।

4
আমি বরং একটি সরল onVisibleToUser()পদ্ধতি বাস্তবায়ন করতাম এবং সেটিকে আমার কাছে কল করা এবং জীবনচক্র কলব্যাকগুলিতে হস্তক্ষেপ করার পরিবর্তে onResume()কাছ থেকে ডাকত । অন্যথায় আমি এই পদ্ধতির সুন্দরভাবে কাজ করে বলে মনে করি, ধন্যবাদ! setUserVisibleHint(boolean)onResume()
স্টিফান হেনিংসেন

1
হ্যাঁ আমি উপরের মন্তব্যে একমত সাধারণভাবে, আপনার শ্রেণীর সর্বজনীন পদ্ধতি থেকে সর্বজনীন পদ্ধতিগুলি কল করা এড়াতে চেষ্টা করুন। একটি ব্যক্তিগত পদ্ধতি তৈরি করুন এবং উভয় সর্বজনীন পদ্ধতি থেকে কল করুন।
জোহান ফ্রানসান

4
setUserVisibleHint হ্রাস করা হয়েছে!
হামিদ রেজা

70

এখানে ব্যবহারের অন্য উপায় onPageChangeListener:

  ViewPager pager = (ViewPager) findByViewId(R.id.viewpager);
  FragmentPagerAdapter adapter = new FragmentPageAdapter(getFragmentManager);
  pager.setAdapter(adapter);
  pager.setOnPageChangeListener(new OnPageChangeListener() {

  public void onPageSelected(int pageNumber) {
    // Just define a callback method in your fragment and call it like this! 
    adapter.getItem(pageNumber).imVisible();

  }

  public void onPageScrolled(int arg0, float arg1, int arg2) {
    // TODO Auto-generated method stub

  }

  public void onPageScrollStateChanged(int arg0) {
    // TODO Auto-generated method stub

  }
});

1
এই সমাধানটি ভাল কাজ করে, ধন্যবাদ। পুরানো প্ল্যাটফর্মগুলির (v4) টুকরা সমর্থন প্যাকেজগুলি ব্যবহার করে যারা বিল্ডিংয়ের জন্য এটির প্রস্তাবিত সমাধান হওয়া উচিত
ফ্রাঙ্ক ইয়িন

7
এটি লক্ষণীয় যে আপনি যদি ফ্রেগমেন্টস্টেটপেজারএডাপ্টার ব্যবহার করেন এবং getItem () এ নতুন ফ্রেগমেন্ট উদাহরণ ইনস্ট্যান্ট করেন তবে এটি আপনাকে প্রত্যাশিত ফলাফল দিতে পারে না, কারণ আপনি কেবলমাত্র নতুন খণ্ডে রাষ্ট্র স্থাপন করবেন এবং দর্শকের কাছে যেটি পেয়েছিল তা নয় not
বেন পিয়ারসন

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

আমি একই ধরণের সমস্যা। সমস্যা সমাধানে আমাকে সাহায্য করুন। আমার পোস্ট: stackoverflow.com/questions/23115283/...
Jeeten Parmar

এটি অ্যাডাপ্টারের জন্য নাল পয়েন্টার ব্যতিক্রম দিচ্ছে যা আমি টুকরোটির iamVisible পদ্ধতিতে ব্যবহার করছি। আমি কেবলমাত্র নেটওয়ার্কটি থেকে প্রাপ্ত ডেটা সেট করার চেষ্টা করছি যখন খণ্ডটি দৃশ্যমান হয়।
zaphod100.10

58

setUserVisibleHint()আগে কখনও কখনও বলা হয় onCreateView() যা সমস্যার কারণ হয়।

এ থেকে উত্তরণের জন্য আপনাকে isResumed()পাশাপাশি অভ্যন্তর setUserVisibleHint()পদ্ধতিও পরীক্ষা করতে হবে । তবে এই ক্ষেত্রে আমি বুঝতে পেরেছি যে কেবল কল হয়setUserVisibleHint() called যদি অসম্পূর্ণ অংশ পুনরায় শুরু এবং দৃশ্যমান হয়, যখন তৈরি করা হয়েছে।

সুতরাং আপনি যদি খণ্ডের সময় কিছু আপডেট করতে চান তবে visibleআপনার আপডেটের কাজটি এতে onCreate()এবং উভয়ই রেখে দিন setUserVisibleHint():

@Override
public View onCreateView(...){
    ...
    myUIUpdate();
    ...        
}
  ....
@Override
public void setUserVisibleHint(boolean visible){
    super.setUserVisibleHint(visible);
    if (visible && isResumed()){
        myUIUpdate();
    }
}

আপডেট: তবুও আমি বুঝতে পারি যে myUIUpdate()কখনও কখনও দু'বার কল করা হয়, কারণটি হ'ল যদি আপনার 3 টি ট্যাব থাকে এবং এই কোডটি 2 য় ট্যাবে থাকে, যখন আপনি প্রথম 1 ম ট্যাবটি খোলেন, দ্বিতীয় ট্যাবটি তৈরি হয় এমনকি এটি দৃশ্যমান নয় এবং myUIUpdate()বলা হয়। তারপরে আপনি যখন 2 য় ট্যাবটিতে স্যুইপ করেন তখন myUIUpdate()থেকে কল if (visible && isResumed())করা হয় এবং ফলস্বরূপ, myUIUpdate()সেকেন্ডে দু'বার কল আসতে পারে।

অন্যান্য সমস্যা হয় !visiblesetUserVisibleHintবলা পরার উভয় 1) যখন আপনি টুকরা পর্দা প্রথমবার স্যুইচ টুকরা পর্দা এবং 2) সামনে এটি তৈরি করা হয়, এর বাইরে যেতে।

সমাধান:

private boolean fragmentResume=false;
private boolean fragmentVisible=false;
private boolean fragmentOnCreated=false;
...

@Override
public View onCreateView(...){
    ...
    //Initialize variables
    if (!fragmentResume && fragmentVisible){   //only when first time fragment is created
        myUIUpdate();
    }
    ...        
}

@Override
public void setUserVisibleHint(boolean visible){
    super.setUserVisibleHint(visible);
    if (visible && isResumed()){   // only at fragment screen is resumed
        fragmentResume=true;
        fragmentVisible=false;
        fragmentOnCreated=true;
        myUIUpdate();
    }else  if (visible){        // only at fragment onCreated
        fragmentResume=false;
        fragmentVisible=true;
        fragmentOnCreated=true;
    }
    else if(!visible && fragmentOnCreated){// only when you go out of fragment screen
        fragmentVisible=false;
        fragmentResume=false;
    }
}

ব্যাখ্যা:

fragmentResume, fragmentVisible: নিশ্চিত করে myUIUpdate()onCreateView()শুধুমাত্র যখন টুকরা তৈরি করা হয় এবং দৃশ্যমান, পুনরায় শুরু না বলা হয়। এটি আপনি প্রথম ট্যাবে থাকা অবস্থায় সমস্যা সমাধান করে, ২ য় ট্যাব দৃশ্যমান না হলেও তৈরি করা হয়। এটি সমাধান করে এবং খণ্ডের স্ক্রিনটি কখন প্রদর্শিত হবে তা পরীক্ষা করে onCreate

fragmentOnCreated: নিশ্চিত করুন যে খণ্ডটি দৃশ্যমান নয়, এবং যখন আপনি প্রথমবার খণ্ড তৈরি করবেন তখন কল হয় না। সুতরাং এখন আপনি যদি খণ্ডটি সোয়াইপ করেন তখন ক্লজটি কেবল তখনই কল হয়।

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


1
আপনার সমাধানটি একটি দৃশ্যের ব্যতীত পুরোপুরি কার্যকরভাবে কাজ করে, যখন খণ্ডটি সাধারণত খোলায় এবং তারপরে আপনি অন্য একটি টুকরা দিয়ে এটি প্রতিস্থাপন করতে কিছু বোতাম টিপুন এবং তারপরে ব্যাকস্ট্যাক থেকে নতুন টুকরোটিকে পপ করতে ফিরে ক্লিক করুন, এই ক্ষেত্রে setUserVisibleHintকল আসে নি .. ! এবং ভিতরে onCreateViewপদ্ধতি fragmentVisibleছিল false!? তাই খণ্ড খালি দেখালাম ..! কোন চিন্তা.?
আলা আবুজারিফা

28

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

public class BaseFragmentHelpLoadDataWhenVisible extends Fragment {
    protected boolean mIsVisibleToUser; // you can see this variable may absolutely <=> getUserVisibleHint() but it not. Currently, after many test I find that

    /**
     * This method will be called when viewpager creates fragment and when we go to this fragment background or another activity or fragment
     * NOT called when we switch between each page in ViewPager
     */
    @Override
    public void onStart() {
        super.onStart();
        if (mIsVisibleToUser) {
            onVisible();
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        if (mIsVisibleToUser) {
            onInVisible();
        }
    }

    /**
     * This method will called at first time viewpager created and when we switch between each page
     * NOT called when we go to background or another activity (fragment) when we go back
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        mIsVisibleToUser = isVisibleToUser;
        if (isResumed()) { // fragment have created
            if (mIsVisibleToUser) {
                onVisible();
            } else {
                onInVisible();
            }
        }
    }

    public void onVisible() {
        Toast.makeText(getActivity(), TAG + "visible", Toast.LENGTH_SHORT).show();
    }

    public void onInVisible() {
        Toast.makeText(getActivity(), TAG + "invisible", Toast.LENGTH_SHORT).show();
    }
}

বিবরণ আপনি নীচের লগক্যাটটি সাবধানতার সাথে চেক করতে পারেন তবে আমি মনে করি আপনি কেন জানেন যে এই সমাধানটি কেন কাজ করবে

প্রথম লঞ্চ

Fragment1: setUserVisibleHint: isVisibleToUser=false isResumed=false
Fragment2: setUserVisibleHint: isVisibleToUser=false isResumed=false
Fragment3: setUserVisibleHint: isVisibleToUser=false isResumed=false
Fragment1: setUserVisibleHint: isVisibleToUser=true isResumed=false // AT THIS TIME isVisibleToUser=true but fragment still not created. If you do something with View here, you will receive exception
Fragment1: onCreateView
Fragment1: onStart mIsVisibleToUser=true
Fragment2: onCreateView
Fragment3: onCreateView
Fragment2: onStart mIsVisibleToUser=false
Fragment3: onStart mIsVisibleToUser=false

পৃষ্ঠা 2 এ যান

Fragment1: setUserVisibleHint: isVisibleToUser=false isResumed=true
Fragment2: setUserVisibleHint: isVisibleToUser=true isResumed=true

পৃষ্ঠা 3 এ যান

Fragment2: setUserVisibleHint: isVisibleToUser=false isResumed=true
Fragment3: setUserVisibleHint: isVisibleToUser=true isResumed=true

পটভূমিতে যান:

Fragment1: onStop mIsVisibleToUser=false
Fragment2: onStop mIsVisibleToUser=false
Fragment3: onStop mIsVisibleToUser=true

অগ্রভাগে যান

Fragment1: onStart mIsVisibleToUser=false
Fragment2: onStart mIsVisibleToUser=false
Fragment3: onStart mIsVisibleToUser=true

ডেমো প্রকল্প এখানে

আশা করি এটি সাহায্য করবে


1
এটি যখন কাজ করে না তখন কোনও খণ্ডে অন্য ভিউ পেজার থাকে যা এতে খণ্ড থাকে।
শিহাব উদ্দিন

দুঃখিত, আমি এই মুহুর্তে উত্তরটি পোস্ট করতে পারি না কারণ আমার পর্যাপ্ত সময় নেই, যদি সম্ভব হয় তবে আপনার সমস্যাটি সম্পর্কে আমার গিটটি এখানে উল্লেখ করুন github.com/FanVanLinh/AndroidViewPagerSkeleton/tree/masterSubChildContainerFragmentসনাক্তকরণের জন্য ব্যবহৃত হয় a fragment has another view pager which also consists fragment। আপনি মিশ্রণ SubChildContainerFragmentএবং ChildContainerFragment1 ক্লাস করতে পারেন । আশা করি এটি সাহায্য করবে। আমি পুরো উত্তরটি পরে পোস্ট করব
ফান ভ্যান লিনহ

26
package com.example.com.ui.fragment;


import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.com.R;

public class SubscribeFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_subscribe, container, false);
        return view;
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

        if (isVisibleToUser) {
            // called here
        }
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }
}

2
এটি গ্রহণযোগ্য উত্তর হওয়া উচিত। Android.app.Fraament এর সাথেও কাজ করে, যা একটি বিশাল বোনাস।
রাজভি

setUserVisibleHintঅননুমোদিত
ekashking

23

ইন ViewPager2এবং ViewPagerসংস্করণ থেকে androidx.fragment:fragment:1.1.0আপনি শুধু ব্যবহার করতে পারেন onPauseএবং onResumecallbacks নির্ধারণ করতে যা টুকরা বর্তমানে ব্যবহারকারীর জন্য দৃশ্যমান হয়। onResumeকলব্যাক কল করা হয় যখন খণ্ডটি দৃশ্যমান হয়ে যায় এবং onPauseযখন এটি দৃশ্যমান হয়ে যায়।

ভিউপেজার 2 এর ক্ষেত্রে এটি ডিফল্ট আচরণ তবে একই আচরণটি পুরানো ভালের জন্য ViewPagerসহজেই সক্ষম করা যায়।

প্রথম ভিউপিজারে এই আচরণটি সক্ষম করতে আপনাকে কনস্ট্রাক্টরের FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENTদ্বিতীয় যুক্তি হিসাবে প্যারামিটারটি পাস করতে হবে FragmentPagerAdapter

FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)

দ্রষ্টব্য: একটি প্যারামিটার সহ setUserVisibleHint()পদ্ধতি এবং FragmentPagerAdapterনির্মাতাকে এখন অ্যান্ড্রয়েড জেটপ্যাক থেকে ফ্রেগমেন্টের নতুন সংস্করণে ছাড় দেওয়া হয়েছে।


1
সুন্দর সমাধানের জন্য ধন্যবাদ। আমি দীর্ঘদিন থেকে এটি সন্ধান করছিলাম। দুর্দান্ত কাজ
অনুরাগ শ্রীবাস্তব

1
ভিউপ্যাজার 2-এর জন্য BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT বিকল্পটি ডিফল্ট আচরণ নয়, আপনাকে এটি ম্যানুয়ালি সেট করতে হবে। এই বিকল্পটি সেট করার সময় আপনার সমাধানটি আমার পক্ষে কাজ করেছিল। ধন্যবাদ।
ড্রাইভ করুন

1
এপ্রি 2020 হিসাবে এটি আপডেট হওয়া সমাধান এবং একটি কবজির মতো কাজ করে।
প্রকাশ

1
@ 4 টোনাইন দয়া করে এই উত্তরটিকে সঠিক উত্তর হিসাবে গ্রহণ করার বিষয়টি বিবেচনা করুন, যেহেতু এখন পর্যন্ত এটি সঠিক এবং বেশিরভাগ উত্তর হ'ল অবহিত সেট-ব্যবহারকারীর দৃষ্টিভঙ্গি পদ্ধতি ব্যবহার করছে
জর্ন রিগটার

16

ওভাররাইড setPrimaryItem()মধ্যে FragmentPagerAdapterউপশ্রেণী। আমি এই পদ্ধতিটি ব্যবহার করি এবং এটি ভালভাবে কাজ করে।

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    // This is what calls setMenuVisibility() on the fragments
    super.setPrimaryItem(container, position, object);

    if (object instanceof MyWhizBangFragment) {
        MyWhizBangFragment fragment = (MyWhizBangFragment) object;
        fragment.doTheThingYouNeedToDoOnBecomingVisible();
    }
}

1
এটি প্রায় কাজ করেছে তবে এনপিইতে সমস্যা হয়েছে এবং একাধিকবার কল করা হচ্ছে। নীচে একটি বিকল্প পোস্ট!
Gober


@ গুবার প্রথমে অবজেক্ট অবজেক্টটি সংরক্ষণ করুন এবং ফ্রেগমেন্টস্টেট অ্যাডাপ্টার যেমন সেটপ্রাইমারি আইটেম () পদ্ধতিতে করুন ঠিক তেমন অবজেক্ট অবজেক্টের সাথে ফলোআপ কলটি চেক এবং উপেক্ষা করুন
ওয়াংলুগাও

12

তার Fragment.onHiddenChanged()জন্য ওভাররাইড করুন ।

public void onHiddenChanged(boolean hidden)

কল করা হয় যখন খণ্ডটির লুকানো অবস্থা (যেমন ফিরে আসে isHidden()) পরিবর্তিত হয়। খণ্ডগুলি গোপন নয় আউট শুরু; যখনই খণ্ডটি এর থেকে রাজ্য পরিবর্তন করবে তখনই এটি ডাকা হবে।

পরামিতি
hidden- boolean: খণ্ডটি যদি এখন লুকানো থাকে তবে সত্য যদি এটি দৃশ্যমান না হয় false


3
এই পদ্ধতিটি এখনই
অবহেলা

4
@ নীচে আপনি কোথায় দেখছেন এটি হ্রাস করা হয়েছে? বিকাশকারী.অ্যান্ড্রয়েড.
com

1
আমি এটি সবেমাত্র সাফল্যের সাথে ব্যবহার করেছি এবং ডকুমেন্টেশন মনে হয় না যে এটি হ্রাস পেয়েছে।
ট্রেভর

1
@ ব্লু, 4.1 (এপিআই 16) এ এটি এখনও অবচয় করা হয়নি।
ড্যান

8
আমি এপিআই লেভেল 19 ব্যবহার করছি এবং নিশ্চিত করতে পারি যে এটি অবনমিত না হওয়া অবস্থায় এটি বিজ্ঞাপন হিসাবে কাজ করে না। উদাহরণস্বরূপ, খণ্ডটি অন্য খণ্ডের দ্বারা গোপন করা হলে onHidedChanged বলা হয় না।

4

আমি এটি আবিষ্কার করেছি onCreateOptionsMenuএবং onPrepareOptionsMenuকেবলমাত্র খণ্ডের ক্ষেত্রে প্রদর্শিত পদ্ধতিগুলি সত্যই দৃশ্যমান। আমি এর মতো আচরণ করে এমন কোন পদ্ধতি খুঁজে পেলাম না, আমি চেষ্টাও করেছি OnPageChangeListenerকিন্তু এটি পরিস্থিতিগুলির জন্য কার্যকর হয়নি, উদাহরণস্বরূপ, onCreateপদ্ধতিতে আমার একটি পরিবর্তনশীল সূচনা প্রয়োজন ।

সুতরাং এই দু'টি পদ্ধতি বিশেষত সামান্য এবং সংক্ষিপ্ত কাজের জন্য এই সমস্যাটির জন্য কর্মসংস্থান হিসাবে ব্যবহার করা যেতে পারে।

আমি মনে করি, এটি সবচেয়ে ভাল সমাধান তবে সেরা নয়। আমি এটি ব্যবহার করব তবে একই সাথে আরও ভাল সমাধানের জন্য অপেক্ষা করব।

শুভেচ্ছা।


2

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

private int mCurrentPosition = -1;

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    super.setPrimaryItem(container, position, object);

    if (position == mCurrentPosition) {
        return;
    }

    if (object instanceof MyWhizBangFragment) {
        MyWhizBangFragment fragment = (MyWhizBangFragment) object;

        if (fragment.isResumed()) {
            mCurrentPosition = position;
            fragment.doTheThingYouNeedToDoOnBecomingVisible();
        }
    }
}

2

খণ্ডের ভিতরে নিম্নলিখিত কোড যুক্ত করুন

@Override
public void setMenuVisibility(final boolean visible) 
 {
    super.setMenuVisibility(visible);
    if (visible && isResumed()) 
     {

     }
}

এটি শুধুমাত্র ভিউপাগারফ্রেমেটমেন্টগুলির জন্য কাজ করে। সাধারণ ক্রিয়াকলাপের টুকরো জন্য নয়।
অ্যান্ড্রয়েডগুই

2

FragmentStatePagerAdaptersএবং 3 টি ট্যাব নিয়ে কাজ করার সময় আমি একই সমস্যার মুখোমুখি হয়েছি । যখনই প্রথম ট্যাবটি ক্লিক করা হয়েছিল তখনই আমাকে একটি দিলোগ দেখাতে হয়েছিল এবং অন্য ট্যাবগুলিতে ক্লিক করে এটি লুকিয়ে রাখতে হয়েছিল।

setUserVisibleHint()একাই ওভাররাইড করা বর্তমান দৃশ্যমান খণ্ডটি খুঁজে পেতে সহায়তা করে না।

তৃতীয় ট্যাব -----> প্রথম ট্যাব থেকে ক্লিক করার সময়। এটি দ্বিতীয় খণ্ড এবং প্রথম খণ্ডের জন্য দুবার ট্রিগার করেছে red আমি এটি পুনরায় সেট করা () পদ্ধতির সাথে একত্রিত করেছি।

    @Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    isVisible = isVisibleToUser;

    // Make sure that fragment is currently visible
    if (!isVisible && isResumed()) {
        // Call code when Fragment not visible
    } else if (isVisible && isResumed()) {
       // Call code when Fragment becomes visible.
    }

}

2

আমাদের এমভিপি-র একটি বিশেষ কেস রয়েছে যেখানে খণ্ডটি উপস্থাপককে দৃশ্যটি দৃশ্যমান হয়ে গেছে এবং উপস্থাপকটি ইন ডেকার ইনজেকশনের মাধ্যমে ইনজেকশনের মাধ্যমে উপস্থাপককে অবহিত করতে হবে fragment.onAttach()

setUserVisibleHint()যথেষ্ট নয়, আমরা 3 টি পৃথক ক্ষেত্রে সনাক্ত করেছি যেগুলি চিহ্নিত করা দরকার ( onAttach()উল্লেখ করা হয়েছে যাতে উপস্থাপক কখন উপলব্ধ থাকে তা জানতে পারেন):

  1. খণ্ডটি সবেমাত্র তৈরি করা হয়েছে। সিস্টেমটি নিম্নলিখিত কলগুলি করে:

    setUserVisibleHint() // before fragment's lifecycle calls, so presenter is null
    onAttach()
    ...
    onResume()
  2. টুকরাটি ইতিমধ্যে তৈরি হয়েছে এবং হোম বোতাম টিপছে। অ্যাপ্লিকেশনটিকে অগ্রভাগে পুনরুদ্ধার করার সময়, এটিকে বলা হয়:

    onResume()
  3. ওরিয়েন্টেশন পরিবর্তন:

    onAttach() // presenter available
    onResume()
    setUserVisibleHint()

আমরা কেবল একবার উপস্থাপকের কাছে দৃশ্যমানতার ইঙ্গিতটি পেতে চাই, তাই আমরা এটি এটি করি:

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View root = inflater.inflate(R.layout.fragment_list, container, false);
    setHasOptionsMenu(true);

    if (savedInstanceState != null) {
        lastOrientation = savedInstanceState.getInt(STATE_LAST_ORIENTATION,
              getResources().getConfiguration().orientation);
    } else {
        lastOrientation = getResources().getConfiguration().orientation;
    }

    return root;
}

@Override
public void onResume() {
    super.onResume();
    presenter.onResume();

    int orientation = getResources().getConfiguration().orientation;
    if (orientation == lastOrientation) {
        if (getUserVisibleHint()) {
            presenter.onViewBecomesVisible();
        }
    }
    lastOrientation = orientation;
}

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (presenter != null && isResumed() && isVisibleToUser) {
        presenter.onViewBecomesVisible();
    }
}

@Override public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt(STATE_LAST_ORIENTATION, lastOrientation);
}

2

দ্বারা সনাক্ত করা হচ্ছে focused view!

এটি আমার পক্ষে কাজ করে

public static boolean isFragmentVisible(Fragment fragment) {
    Activity activity = fragment.getActivity();
    View focusedView = fragment.getView().findFocus();
    return activity != null
            && focusedView != null
            && focusedView == activity.getWindow().getDecorView().findFocus();
}

1

আমি যখন ভিউপ্যাজারের টুকরাটি অন-স্ক্রিনটি ব্যবহারকারীর জন্য দেখার জন্য স্ক্রিনে ছিল তখন যখন আমি টাইমার ফায়ার করার চেষ্টা করছিলাম তখন আমি এই সমস্যার মুখোমুখি হয়েছি।

ব্যবহারকারীটি খণ্ডটি দেখার আগে টাইমারটি সর্বদা শুরু হয়। এর কারণ onResume()আমরা খণ্ডটি দেখার আগে টুকরোটিতে পদ্ধতিটি বলা হয়।

আমার সমাধানটি ছিল onResume()পদ্ধতিটিতে একটি চেক করা । আমি একটি নির্দিষ্ট পদ্ধতিতে 'foo ()' কল করতে চেয়েছিলাম যখন খণ্ড 8 তখন ভিউ পেজারের বর্তমান খণ্ড ছিল।

@Override
public void onResume() {
    super.onResume();
    if(viewPager.getCurrentItem() == 8){
        foo();
        //Your code here. Executed when fragment is seen by user.
    }
}

আশাকরি এটা সাহায্য করবে. আমি এই সমস্যাটি অনেকটা পপ আপ দেখেছি। এটি আমি দেখেছি সবচেয়ে সহজ সমাধান বলে মনে হচ্ছে। অন্যান্য অনেকগুলি নিম্ন API গুলি ইত্যাদির সাথে সামঞ্জস্যপূর্ণ নয়


1

আমারও একই প্রশ্ন ছিল. ViewPagerঅন্যান্য খণ্ড জীবন চক্র ইভেন্টগুলি কার্যকর করে এবং আমি সেই আচরণটি পরিবর্তন করতে পারি না could আমি টুকরা এবং উপলব্ধ অ্যানিমেশন ব্যবহার করে একটি সাধারণ পেজার লিখেছিলাম। SimplePager


1

আমি এটি ব্যবহার করেছি এবং এটি কাজ করেছে!

mContext.getWindow().getDecorView().isShown() //boolean

1

আমি বাচ্চাদের টুকরো টুকরো করে সেকশনপেজারএডাপ্টারকে সমর্থন করি তাই প্রচুর মাথা ব্যাথার পরে অবশেষে এই বিষয়টির সমাধানের ভিত্তিতে আমি ওয়ার্কিং সংস্করণ পেয়েছি:

public abstract class BaseFragment extends Fragment {

    private boolean visible;
    private boolean visibilityHintChanged;

    /**
     * Called when the visibility of the fragment changed
     */
    protected void onVisibilityChanged(View view, boolean visible) {

    }

    private void triggerVisibilityChangedIfNeeded(boolean visible) {
        if (this.visible == visible || getActivity() == null || getView() == null) {
            return;
        }
        this.visible = visible;
        onVisibilityChanged(getView(), visible);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (!visibilityHintChanged) {
            setUserVisibleHint(false);
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        if (getUserVisibleHint() && !isHidden()) {
            triggerVisibilityChangedIfNeeded(true);
        }
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        triggerVisibilityChangedIfNeeded(!hidden);
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        visibilityHintChanged = true;
        if (isVisibleToUser && isResumed() && !isHidden()) {
            triggerVisibilityChangedIfNeeded(true);
        } else if (!isVisibleToUser) {
            triggerVisibilityChangedIfNeeded(false);
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        triggerVisibilityChangedIfNeeded(false);
    }

    @Override
    public void onStop() {
        super.onStop();
        triggerVisibilityChangedIfNeeded(false);
    }

    protected boolean isReallyVisible() {
        return visible;
    }
}

উল্লেখ করতে ভুলে গেছেন, একবার আপনি পিতা-মাতার টুকরা সেট ফ্রেগমেন্টে বাচ্চা টুকরা যোগ করেন setsetUserVisibleHint (সত্য);
Andoctorey

এবং সন্তানের টুকরো যোগ করার জন্য getFramentManager () এর পরিবর্তে getChildFraamentManager () ব্যবহার করতে ভুলবেন না।
Andoctorey

0

নোট যে setUserVisibleHint(false)ক্রিয়াকলাপ / টুকরা স্টপ নেভিগেশন কল করা হয় না। আপনার এখনও register/unregisterকোনও শ্রোতা / ইত্যাদি সঠিকভাবে শুরু করতে / থামাতে চেক করতে হবে ।

এছাড়াও, setUserVisibleHint(false)যদি আপনার খণ্ডটি অ-দৃশ্যমান অবস্থায় শুরু হয় তবে আপনি পাবেন ; আপনি unregisterসেখানে যেতে চান না যেহেতু আপনি আগে কখনও নিবন্ধন করেন নি।

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

    if (getUserVisibleHint()) {
        // register
    }
}

@Override
public void onStop() {
    if (getUserVisibleHint()) {
        // unregister
    }

    super.onStop();
}

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);

    if (isVisibleToUser && isResumed()) {
        // register

        if (!mHasBeenVisible) {
            mHasBeenVisible = true;
        }
    } else if (mHasBeenVisible){
        // unregister
    }
}

0

প্রয়োগের একটি সহজ উপায় ব্যবহারকারী খণ্ডে যাওয়ার আগে লগ ইন করেছেন কিনা তা পরীক্ষা করে দেখছে ।

আপনার মেইনএ্যাকটিভিটিতে আপনি নেভিগেশন আইটেমসিলিগ্রেটেড পদ্ধতির অভ্যন্তরে এমন কিছু করতে পারেন ।

 case R.id.nav_profile_side:


                if (User_is_logged_in) {

                    fragmentManager.beginTransaction()
                            .replace(R.id.content_frame
                                    , new FragmentProfile())
                            .commit();
                }else {

                    ShowLoginOrRegisterDialog(fragmentManager);

                }

                break;

তবে, আপনি যদি নেভিগেশন ড্রয়ার ব্যবহার করছেন তবে ড্রয়ারের নির্বাচনটি প্রোফাইলে পরিবর্তিত হবে যদিও আমরা প্রোফাইলফ্র্যামেন্টে যাইনি।

বর্তমান নির্বাচনে নির্বাচনটি পুনরায় সেট করতে নীচের কোডটি চালান

        navigationView.getMenu().getItem(0).setChecked(true);

-4

আমি সম্পর্কিত ফ্রেগমেন্টস্টেটপেজারএডাপ্টারের কাউন্ট পদ্ধতিটি ওভাররড করেছি এবং এটি গোপনের জন্য পৃষ্ঠার সংখ্যাটি মোট গণনা বিয়োগ করে দিবে:

 public class MyAdapter : Android.Support.V13.App.FragmentStatePagerAdapter
 {   
     private List<Fragment> _fragments;

     public int TrimmedPages { get; set; }

     public MyAdapter(Android.App.FragmentManager fm) : base(fm) { }

     public MyAdapter(Android.App.FragmentManager fm, List<Android.App.Fragment> fragments) : base(fm)
     {
         _fragments = fragments;

         TrimmedPages = 0;
     }

     public override int Count
     {
         //get { return _fragments.Count; }
         get { return _fragments.Count - TrimmedPages; }
     }
 }

সুতরাং, যদি প্রাথমিকভাবে ভিউপাগারে 3 টি টুকরো যোগ করা হয় এবং কিছু শর্ত পূরণ না হওয়া পর্যন্ত কেবল প্রথম 2 টি দেখানো উচিত, ট্রিমমেডপেজগুলি 1 এ সেট করে পৃষ্ঠা গণনাটি ওভাররাইড করে এবং এটি কেবল প্রথম দুটি পৃষ্ঠা দেখানো উচিত should

এটি শেষ পৃষ্ঠাগুলির জন্য ভাল কাজ করে, তবে শুরু বা মাঝের অংশগুলির জন্য সত্যিই সাহায্য করবে না (যদিও এটি করার প্রচুর উপায় রয়েছে)।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.