android - How do I add a new tab with fragments -
so want create 3 tabs, different each other. xml have covered. not how create tabs without crashing app.
i have implemented swipe tab viewpage.
http://developer.android.com/training/implementing-navigation/lateral.html http://www.androidhive.info/2013/10/android-tab-layout-with-swipeable-views-1/
and part of http://www.java2s.com/code/android/ui/demonstrateshowfragmentscanparticipateintheoptionsmenu.htm
when try go next tab(swipe work no problem) error:
07-08 22:07:57.414: e/androidruntime(6865): fatal exception: main 07-08 22:07:57.414: e/androidruntime(6865): process: com.cyberdog.magiceasydraft, pid: 6865 07-08 22:07:57.414: e/androidruntime(6865): java.lang.nullpointerexception: attempt invoke virtual method 'void android.support.v4.view.viewpager.setcurrentitem(int)' on null object reference 07-08 22:07:57.414: e/androidruntime(6865): @ com.cyberdog.magiceasydraft.addplayersfragmenttab.dopositiveclick(addplayersfragmenttab.java:113) 07-08 22:07:57.414: e/androidruntime(6865): @ com.cyberdog.magiceasydraft.addplayersfragmenttab$myalertdialogfragment$1.onclick(addplayersfragmenttab.java:165) 07-08 22:07:57.414: e/androidruntime(6865): @ com.android.internal.app.alertcontroller$buttonhandler.handlemessage(alertcontroller.java:160) 07-08 22:07:57.414: e/androidruntime(6865): @ android.os.handler.dispatchmessage(handler.java:102) 07-08 22:07:57.414: e/androidruntime(6865): @ android.os.looper.loop(looper.java:135) 07-08 22:07:57.414: e/androidruntime(6865): @ android.app.activitythread.main(activitythread.java:5274) 07-08 22:07:57.414: e/androidruntime(6865): @ java.lang.reflect.method.invoke(native method) 07-08 22:07:57.414: e/androidruntime(6865): @ java.lang.reflect.method.invoke(method.java:372) 07-08 22:07:57.414: e/androidruntime(6865): @ com.android.internal.os.zygoteinit$methodandargscaller.run(zygoteinit.java:909) 07-08 22:07:57.414: e/androidruntime(6865): @ com.android.internal.os.zygoteinit.main(zygoteinit.java:704)
so.. doing wrong here? can see there null reference create round fragment... have no clue how fix this. first time working fragments , tabs.
code: main activity:
public class createdraft extends fragmentactivity implements actionbar.tablistener { private viewpager viewpager; private fragmentpageadapter madapter; private actionbar actionbar; private fragment addplayer, createround,score; private string[] tabs = { "add players", "create round", "score" }; public static final string custom_fragment_key ="add_player_tab"; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_create_draft); viewpager = (viewpager) findviewbyid(r.id.activity_viewpager_main); actionbar = getactionbar(); madapter = new fragmentpageadapter(getsupportfragmentmanager()); viewpager.setadapter(madapter); actionbar.sethomebuttonenabled(false); actionbar.setnavigationmode(actionbar.navigation_mode_tabs); if(savedinstancestate == null){ fragmentmanager fm = getsupportfragmentmanager(); android.support.v4.app.fragmenttransaction ft = fm.begintransaction(); addplayer = fm.findfragmentbytag("add players"); if(addplayer == null){ addplayer = new addplayersfragmenttab(); ft.add(addplayer, "add players"); } createround = fm.findfragmentbytag("create round"); if(createround == null){ createround = new createroundfragmenttab(); ft.add(createround, "create round"); } score = fm.findfragmentbytag("score"); if(score == null){ score = new scoreresultfragmenttab(); ft.add(score, "score"); } ft.commit(); } // (string tab_name : tabs) { actionbar.addtab(actionbar.newtab().settext(tab_name) .settablistener(this)); } viewpager.setonpagechangelistener(new viewpager.onpagechangelistener() { @override public void onpageselected(int position) { // on changing page // make respected tab selected actionbar.setselectednavigationitem(position); } @override public void onpagescrolled(int arg0, float arg1, int arg2) { } @override public void onpagescrollstatechanged(int arg0) { } }); } public void passbundletofragment(int position){ if(true){ } } @override public void ontabreselected(tab tab, fragmenttransaction ft) { view focus = getcurrentfocus(); if (focus != null) { hiddenkeyboard(focus); } } @override public void ontabselected(tab tab, fragmenttransaction ft) { // on tab selected // show respected fragment view viewpager.setcurrentitem(tab.getposition()); view focus = getcurrentfocus(); if (focus != null) { hiddenkeyboard(focus); } } @override public void ontabunselected(tab tab, fragmenttransaction ft) { view focus = getcurrentfocus(); if (focus != null) { hiddenkeyboard(focus); } } private void hiddenkeyboard(view v) { inputmethodmanager keyboard = (inputmethodmanager) getsystemservice(context.input_method_service); keyboard.hidesoftinputfromwindow(v.getwindowtoken(), 0); } }
one of fragments(others don't contain code yet):
public class addplayersfragmenttab extends fragment { private button addplayer, createdraft; private edittext evaddplayer; private viewpager viewpager; private list<player> players; private listview lvaddedplayers; listadapter adapter; private boolean buttoncreatedraftpressed= false; public boolean isbuttoncreatedraftpressed() { return buttoncreatedraftpressed; } public void setbuttoncreatedraftpressed(boolean buttoncreatedraftpressed) { this.buttoncreatedraftpressed = buttoncreatedraftpressed; } @override public view oncreateview(layoutinflater inflater, viewgroup container, bundle savedinstancestate) { view rootview = inflater.inflate(r.layout.draft_adding_players, container, false); initialiseeditandtext(rootview); players = new arraylist<player>(); lvaddedplayers = (listview) rootview.findviewbyid( r.id.lv_players_adding); adapter = new listadapter(rootview.getcontext(), players); lvaddedplayers.setadapter(adapter); addplayer = (button) rootview.findviewbyid(r.id.button_total_player); createdraft = (button) rootview.findviewbyid(r.id.button_create_draft); addplayer.setonclicklistener(new onclicklistener() { @override public void onclick(view v) { player player = new player(evaddplayer.gettext().tostring()); players.add(player); adapter.notifydatasetchanged(); inputmethodmanager imm = (inputmethodmanager) getactivity() .getsystemservice(context.input_method_service); imm.hidesoftinputfromwindow(getview().getwindowtoken(), 0); } }); createdraft.setonclicklistener(new onclicklistener() { @override public void onclick(view v) { if (adapter != null && players != null) { createdraft(players.size()); } else { toast.maketext(getactivity(), "add minimal 3 players start draft.", toast.length_long).show(); } } }); return rootview; } public void showdialog(){ dialogfragment newfragment = new myalertdialogfragment().newinstance(r.string.recreate_draft); newfragment.show(getfragmentmanager(), "dialog"); } public void dopositiveclick(){ viewpager.setcurrentitem(1); } public void donegativeclick(){ } public int gettotalplayers() { return players.size(); } public list<player> getplayersnames() { return players; } public void initialiseeditandtext(view rootview) { evaddplayer = (edittext) rootview.findviewbyid(r.id.et_player_name); } public void createdraft(int totalplayers) { if (totalplayers >= 3 && totalplayers <= 16) { showdialog(); } else { toast.maketext(getactivity(), "minimum of 3 , maximum of 16 players.", toast.length_long).show(); } } public class myalertdialogfragment extends dialogfragment{ public myalertdialogfragment newinstance(int title){ myalertdialogfragment frag = new myalertdialogfragment(); bundle args = new bundle(); args.putint("title", title); frag.setarguments(args); return frag; } @override public dialog oncreatedialog(bundle savedinstancestate) { int title = getarguments().getint("title"); return new alertdialog.builder(getactivity()) .seticon(r.drawable.abc_ic_search) .settitle(title) .setpositivebutton("r.string.alert_dialog_ok", new dialoginterface.onclicklistener() { public void onclick(dialoginterface dialog, int whichbutton) { addplayersfragmenttab.this.dopositiveclick(); } } ) .setnegativebutton("r.string.alert_dialog_cancel", new dialoginterface.onclicklistener() { public void onclick(dialoginterface dialog, int whichbutton) { addplayersfragmenttab.this.donegativeclick(); } } ) .create(); } } }
edit:
pageadpter:
public fragmentpageadapter(fragmentmanager fm) { super(fm); // todo auto-generated constructor stub } @override public fragment getitem(int index) { switch (index) { case 0: // top rated fragment activity return new addplayersfragmenttab(); case 1: // games fragment activity return new createroundfragmenttab(); case 2: // movies fragment activity return new scoreresultfragmenttab(); } return null; } @override public int getcount() { // todo auto-generated method stub return 3; } }
edit 2:
i followed passing of data activity, did work, if wanted pass data activity(that got data addplayertab) getting null reference again, time think becuase id wrong. layoutfile dont use . how find fragment?
code: interface implementation of addplayertab:
@override public void onbuttonclickcreateround(int position, list<player> players) { viewpager.setcurrentitem(position); this.players = players; getplayer(); }
code in addplayertab:
public interface gotocreateroundlistener{ public void onbuttonclickcreateround(int position, list<player> players); } public void onattach(activity activity){ super.onattach(activity); try{ gocreateround = (gotocreateroundlistener)activity; }catch(classcastexception e){ throw new classcastexception(activity.tostring()+" must implement gotoroundlistener"); } } public void createdraft(int totalplayers) { if (totalplayers >= 3 && totalplayers <= 16) { gocreateround.onbuttonclickcreateround(1, players); } else { toast.maketext(getactivity(), "minimum of 3 , maximum of 16 players.", toast.length_long).show(); } }
this interface implementation passing data createroundtab:
@override public void getplayer() { createroundfragmenttab createroundfragmenttab = (createroundfragmenttab)getsupportfragmentmanager().findfragmentbyid(r.layout.create_round); createroundfragmenttab.makerandomfirstround(players); }
code in createroundtab:
public interface getplayersfromaddplayerslistener{ public void getplayer(); } public void onattach(activity activity){ super.onattach(activity); try{ getplayers = (getplayersfromaddplayerslistener)activity; }catch(classcastexception e){ throw new classcastexception(activity.tostring()+" must implement getplayersfromaddplayerslistener"); } }
i've shared point on fragment
instantiation above i'll quote myself again.
that whole
if (savedinstance == null)
block not required becausefragment
instantiation job ofpageradapter
.viewpager
callpageradapter#getitem()
when sees fit to.
although, it's obvious nullpointerexception
caused uninitialized viewpager
reference inside addplayersfragmenttab
, whole approach of either passing view pager fragment @ creation or fragment accessing through getter wrong.
the reason fragment self-contained reusable implementation of part of ui , hence should not couple activity hosting it. once couple view pager, can never host fragment in other normal activity again. in short, fragment not remain reusable anymore.
so, how fragment supposed communicate host activity? well, using callback interfaces. here short tutorial official android developers site: communicating other fragments works same requesting activity on behalf of fragment.
in case, inform main activity user pressed ok @ alert dialog , activity respond moving next tab using view pager.
usually when want catch hold of fragment
again, either use findfragmentbyid()
or custom tag findfragmentbytag()
. but, whole viewpager
, pageradapter
doesn't expose these properties us.
so, enable fragment look-ups, need hold references them inside pageradapter
. along lines of following.
map<string, fragment> mfragments = new hashmap<>(3); ... @override public fragment getitem(int index) { ... } @override public object instantiateitem(viewgroup container, int position) { // super calls getitem() if fragment not instantiated fragment fragment = (fragment) super.instantiateitem(container, position); mfragments.put(fragment.getclass().getsimplename(), fragment); return fragment; } public fragment getfragment(string name) { return mfragments.get(name); } @override public int getcount() { return 3; }
with above changes, getplayer()
implementation become
@override public void getplayer() { createroundfragmenttab createroundfragmenttab = (createroundfragmenttab) ((fragmentpageadapter) madapter).getfragment("createroundfragmenttab"); createroundfragmenttab.makerandomfirstround(players); }
to understand approach in more details please read viewpager , fragments — what's right way store fragment's state?.
as aside, please take @ java naming conventions recommended oracle. long story short, need start class names upper case letter , opposite method names. following these conventions make code easier read , more understandable. currently, class names appear variable names seasoned java developers.
Comments
Post a Comment