Myself trying to develop a sample android app based on this tutorial with bottom bar.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.thirdactivity);
BottomBar bottomBar = BottomBar.attach(this, savedInstanceState);
bottomBar.setItemsFromMenu(R.menu.bottom_menu, new OnMenuTabSelectedListener() {
#Override
public void onMenuItemSelected(int itemId) {
Intent myAct = new Intent();
switch (itemId) {
case R.id.item1:
myAct = new Intent(findViewById(itemId).getContext(), mainactivity.class);
break;
case R.id.item2:
myAct = new Intent(findViewById(itemId).getContext(), secondactivity.class);
break;
case R.id.item3:
myAct = new Intent(findViewById(itemId).getContext(), thirdactivity.class);
break;
}
startActivity(myAct);
}
});
}
But how can i set the third tab as default oncreate the activity. The above code highlights the first tab as selected and no even listened when clicking on first tab. Also later tabs opens the respective activities but not highlights as current tab.
EDIT: Myself can use bottomBar.setDefaultTabPosition(desiredTabId); and it working but it uses high memory. What is the fix?
It is solved by having startActivity() as,
BottomBar bottomBar = BottomBar.attach(this, savedInstanceState);
bottomBar.setItemsFromMenu(R.menu.bottom_menu, new OnMenuTabSelectedListener() {
#Override
public void onMenuItemSelected(int itemId) {
Intent act = new Intent();
if (R.id.item1 == itemId) {
act = new Intent(findViewById(itemId).getContext(), act1.class);
startActivity(act);
overridePendingTransition(R.anim.open_translate, R.anim.close_scale);
}
if (R.id.item2 == itemId) {
act = new Intent(findViewById(itemId).getContext(), act2.class);
}
if (R.id.item3 == itemId) {
act = new Intent(findViewById(itemId).getContext(), act3.class);
startActivity(act);
overridePendingTransition(R.anim.open_translate, R.anim.close_scale);
}
}
});
bottomBar.setDefaultTabPosition(2);
bottomBar.setActiveTabColor("#F3C030");
Try setting the default tab before your set the listener
bottomBar.setDefaultTab(R.id.tab_default);
bottomBar.setOnTabSelectListener(this);
This applies for version 2.0.2
If you set the listener before the default tab, it will be called twice.
Once for tab position 0 and then for anything you set as default, which is usually not desired.
Would be nice to set the default tab before the the creation of bottombar, or a warning in the readme.
Related
I'm able to navigate between the tabs in my TabLayout, but only if I select the tab twice does the indicator highlight follow that selection.
For example, from the home tab I will select the quiz tab. The layout for the quiz displays, but the selected indicator under the tab icon remains on home. If I select quiz a second time, then the indicator will follow.
I'm not sure what I'm doing wrong as I thought what I'd been doing was pretty standard, but here's my code that handles tab selects.
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
switch (tab.getPosition()){
case 1:
Intent infoIntent = new Intent(MainActivity.this, about.class);
MainActivity.this.startActivity(infoIntent);
break;
case 2:
Intent studentIntent = new Intent(MainActivity.this, student.class);
MainActivity.this.startActivity(studentIntent);
break;
case 3:
Intent surveyIntent = new Intent(MainActivity.this, survey.class);
MainActivity.this.startActivity(surveyIntent);
break;
case 4:
Intent quizIntent = new Intent(MainActivity.this, quiz.class);
MainActivity.this.startActivity(quizIntent);
break;
}
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
am i missing something?
It might not be the best way, but I solved this by simply putting
tabLayout.getTabAt(index).select();
in each of my activities onCreate. Thanks for the suggestions
Please keep in mind I'm a beginner in Android, so it is possible that somewhere I overlooked something. Also I have more then one question here, because my approach to the whole project might be wrong.
I have an application that has side menu implemented via DrawerLayout. The "main screen" is a Fragment and with Drawer I create the side menu with a list in it. After that this is how I change the fragments upon clicking on the side menu:
private void displayView(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new HomeFragment();
break;
case 1:
fragment = new FavoritesFragment();
break;
case 2:
fragment = new LastVisitedFragment();
break;
case 3:
fragment = new SettingsFragment();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frame_container, fragment).commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
Log.e("MainActivity", "Error in creating fragment");
}
}
The code above is implemented in my main activity. Next this is how my HomeFragment looks:
(The home fragment is my home page so to say)
public class HomeFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.i("HomeFragment", "OK");
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
rootView.setOnClickListener(new View.OnClickListener() {
#
Override
public void onClick(View v) {
Log.i("HomeFragment", "OK0");
switch (v.getId()) {
case R.id.rec_prod1:
Log.i("HomeFragment", "OK1");
Intent intent1 = new Intent(getActivity(), SingleItemActivity.class);
startActivity(intent1);
break;
case R.id.rec_prod2:
Log.i("HomeFragment", "OK2");
Intent intent2 = new Intent(getActivity(), SingleItemActivity.class);
startActivity(intent2);
break;
case R.id.rec_prod3:
Log.i("HomeFragment", "OK3");
Intent intent3 = new Intent(getActivity(), SingleItemActivity.class);
startActivity(intent3);
break;
}
}
});
return rootView;
}
}
I have tried it with onTouchListener to but didn't work either, the single difference was that with onTouch it entered in to the onTouch method, bet nothing happened after. Also somewhere on this site I have red to set the scrollview clickable=true and all childs to false in order for it to work, but that didn't do either.
Also fragment_home.xml is a custom layout with the Parent being a ScrollView (It's a list with three coloumns and 5 rows but each element is different, they all have an Imageview and different number of textviews, I didn't use a ListView or GridList since each row has a title, and the elements in each row have different layouts) I attach only an overview of it since the real xml code is over 800 lines long.
<ScrollView>
<LinearLayout>
<!--This part repeats 5 times creating each row -->
<TextView>
<LinearLayout>
<!-- This part repeats 3 times for each element of a column -->
<RelativeLayout>
<ImageView>
<!-- This part changes acodringly to the number of textviews, I can have 1 to 3 TextViews here-->
<LinearLayout>
<TextView>
<TexytView>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
So I have two main questions.
1. Why doesn't the clicking/touching work.
2. Is the project structure(architecture) ok like this? The whole idea is that when a click happens some elements take me to a product view screen, while others to a list of product elements (the data that fills all this will come from a server, that's why I started a new Activity in the onClick method).
You either need to set an onclick action via XML (this works for activities), or you need to set it in code (almost like you have it) but assigned to the views themselves
Personally I prefer to define the click actions in the code. I think it makes much more sense when reading a project and you avoid any issues like this. It's also the recommended way to do it and is how most sample code and examples will do it (see Android Documentation)
To define the click via code do it like this:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
View OK3 = rootView.findViewById(R.id.rec_prod3); //pick a better name than i have though
if (OK3 != null) {
OK3.setOnClickListener(new View.OnclickListener() {
Log.i("HomeFragment", "OK3");
Intent intent3 = new Intent(getActivity(), SingleItemActivity.class);
startActivity(intent3);
});
}
Most examples use this method as the alternative of using a switch statement and directing every click through the same method is bad practice - essentially you are hacking a shortcut Google has provided for XML support into doing something it wasn't intended for. For more information as to why it is better to use a dedicated listener, look up Inheritance vs Composition - as a rule "Has A" always beats "Is A" for code readability and maintainability.
You're setting the OnClickListener for the whole fragment, not the actual views you are querying in the switch-statement. Of course the specific code parts are never reached!
This approach should work (and is officially supported by Google and well received by users on Stack Overflow):
public class HomeFragment extends Fragment implements View.OnClickListener {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.i("HomeFragment", "OK");
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
rootView.findViewById(R.id.rec_prod1).setOnClickListener(this);
rootView.findViewById(R.id.rec_prod2).setOnClickListener(this);
rootView.findViewById(R.id.rec_prod3).setOnClickListener(this);
return rootView;
}
#Override
public void onClick(View v) {
Log.i("HomeFragment", "OK0");
switch (v.getId()) {
case R.id.rec_prod1:
Log.i("HomeFragment", "OK1");
Intent intent1 = new Intent(getActivity(), SingleItemActivity.class);
startActivity(intent1);
break;
case R.id.rec_prod2:
Log.i("HomeFragment", "OK2");
Intent intent2 = new Intent(getActivity(), SingleItemActivity.class);
startActivity(intent2);
break;
case R.id.rec_prod3:
Log.i("HomeFragment", "OK3");
Intent intent3 = new Intent(getActivity(), SingleItemActivity.class);
startActivity(intent3);
break;
}
}
}
For further reading:
Setting the onClick via XML would also work, but sadly, only in activities, not in fragments: The method is invoked on the fragment's parent activity (see How to handle button clicks using the XML onClick within Fragments).
Still, the above approach has a disadvantage: onClick is public and thus could be called from outside. For example, the parent activity could call
((View.OnClickListener) homeFragment).onClick(
homeFragment.getView().findViewById(R.id.rec_prod1));
This would fire an onClick event for rec_prod1. IMO, the readability and convenience this approach brings outweighs this. Of course, there are other approaches with their own advantages and disadvantages. Most importantly, to prevent this public access, you can create an anonymous class for each listener (see Nick's answer and its disadvantages) or use the code below instead:
public class HomeFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.i("HomeFragment", "OK");
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
View.OnClickListener onClick = new RecProdClickListener();
rootView.findViewById(R.id.rec_prod1).setOnClickListener(onClick);
rootView.findViewById(R.id.rec_prod2).setOnClickListener(onClick);
rootView.findViewById(R.id.rec_prod3).setOnClickListener(onClick);
return rootView;
}
private class RecProdClickListener implements View.OnClickListener {
#Override
public void onClick(View v) {
Log.i("HomeFragment", "OK0");
switch (v.getId()) {
case R.id.rec_prod1:
Log.i("HomeFragment", "OK1");
Intent intent1 = new Intent(getActivity(), SingleItemActivity.class);
startActivity(intent1);
break;
case R.id.rec_prod2:
Log.i("HomeFragment", "OK2");
Intent intent2 = new Intent(getActivity(), SingleItemActivity.class);
startActivity(intent2);
break;
case R.id.rec_prod3:
Log.i("HomeFragment", "OK3");
Intent intent3 = new Intent(getActivity(), SingleItemActivity.class);
startActivity(intent3);
break;
}
}
}
}
Beside all that several anonymous click listeners will lead to more memory usage and a little bit longer intialization time, whereas reusing a click listener with a switch-statement will make performance a negligibly worse due to cyclomatic complexity.
But you can even mix the different approaches. Ultimately, it's up to your taste. Discussing what's best under what circumstances would belong to programmers.stackexchange and surely is an interesting topic for clean code in Android development.
I already know how to start a one new activity when you click a button, but I have three buttons on the one layout. And I want each of the three buttons on that ONE activity to link to three other activities.
I have on the activity I have called 'main', Button 1 which is called services and I want to link it to the services activity. Button 2 which is called Search and I want it to go to the Search activity and thirdly 'map' which I want to link to the map activity.
Can someone help me do this please? Thanks
EDIT:Also, I'm a beginner with Android coding, could you explain in a little bit more detail please?
So where is problem? Just set that your class will implements View.OnClickListener and override onClick() method a you got it.
public class MainActivity extends Activity implements View.OnClickListener {
// body
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.serviceBtn:
Intent serviceIntent = new Intent(this, ServiceActivity.class);
startActivity(serviceIntent);
break;
case R.id.searchBtn:
Intent searchIntent = new Intent(this, SearchActivity.class);
startActivity(searchIntent);
break;
case R.id.mapBtn:
Intent mapIntent = new Intent(this, MapActivity.class);
startActivity(mapIntent);
break;
}
}
Tie an onclick listener to all three buttons. In the listener, retrieve the ID of the button. Make a variable of type Class. Depending on the value of the button ID, initialize it to the class of the activity to invoke. Then construct an Intent for that class, and call startActivity().
EDIT for hawaii.five-0: here's how I'd do it:
#Override
public void onClick(View view) {
Class c = null;
switch (view.getId()) {
case R.id.serviceBtn:
c = ServiceActivity.class;
break;
case R.id.searchBtn:
c = SearchActivity.class;
break;
case R.id.mapBtn:
c = MapActivity.class;
break;
}
Intent i = new Intent(YourActivity.this, c);
startActivity(i);
}
EDIT2:
class CurrentActivity extends Activity
implements OnClickListener
{
void onCreate(Bundle b)
{
//Other initialization goes here...
((Button)findViewById(R.id.MyButton1)).setOnClickListener(this);
((Button)findViewById(R.id.MyButton2)).setOnClickListener(this);
((Button)findViewById(R.id.MyButton3)).setOnClickListener(this);
}
}
Its very easy dear. Just put this code on button click event
Intent myIntent = new Intent(CurrentActivity.this, NextActivity.class);
CurrentActivity.this.startActivity(myIntent);
which is very easy to start a new activity when the button is clicked. I have given the example for this.
// R.id.btnAdd -> which is present in your layout page
Button btnStart = (Button) findViewById(R.id.btnAdd); // declare button
// declare listener evernt for button
OnClickListener listener = new OnClickListener() {
#Override
public void onClick(View v) {
// declare the Intent for moving another activity
Intent view = new Intent(YourCurrentClassName.this,
anotherClassName.class);
// startActivity is used to navigating the view
startActivity(view);
}
};
// set the listener evernt to button
btnStart.setOnClickListener(listener);
I have been trying to solve this issue now for longer than I care to admit. I'm looking to set up an onClicklistener for my tabs so even if a user is on that tab and they click it the tab reloads. Could someone please point out my error, below is the code i'm using made up from examples from stack overflow so thanks so far! I'm using the getTabHost().setCurrentTab(3) to set it to be run only on the tab 3 but how would I get it so that it calls the specific tab the user clicks on?
I have been using this as a reference: OnClickListener on Tabs not working
public class DamTabs extends TabActivity implements OnClickListener{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Resources res = getResources(); // Resource object to get Drawables
TabHost tabHost = getTabHost(); // The activity TabHost
Intent intent = new Intent(this, Featured.class);
tabHost.addTab(tabHost.newTabSpec("Tab 1")
.setIndicator("Featured", res.getDrawable(R.drawable.ic_tab_main))
.setContent(intent));
Intent intent2 = new Intent(this, Deals.class);
tabHost.addTab(tabHost.newTabSpec("Tab 2")
.setIndicator("Deals", res.getDrawable(R.drawable.ic_tab_setup))
.setContent(intent2));
Intent intent3 = new Intent(this, Events.class);
tabHost.addTab(tabHost.newTabSpec("Tab 3")
.setIndicator("Events", res.getDrawable(R.drawable.ic_tab_setup))
.setContent(intent3));
getTabWidget().getChildAt(3).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (getTabHost().getCurrentTabTag().equals(sort)) {
getTabHost().setCurrentTab(3);
}
}
});
} //End of onCreate
If I understood your problem, I think you should use setOnTabChangedListener() method. Something like this:
mTabHost.setOnTabChangedListener(new OnTabChangeListener() {
public void onTabChanged(String tabId) {
Log.d(debugTag, "onTabChanged: tab number=" + mTabHost.getCurrentTab());
switch (mTabHost.getCurrentTab()) {
case 0:
//do what you want when tab 0 is selected
break;
case 1:
//do what you want when tab 1 is selected
break;
case 2:
//do what you want when tab 2 is selected
break;
default:
break;
}
}
});
And remove the implements OnClickListener.
getTabWidget().getChildAt(3).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (getTabHost().getCurrentTabTag().equals(sort)) {
Events.reloadMe()
}
}
});
I would create a static method in the Activity you want to reload and call it like this. I think this is the easiest way to solve it. You will need some private static variables in the Activity to use this. And make sure these private static Objects aren't null.
In my project, I have two tabs and a button. For two tabs,I have two activities and button calling different activity. the thing is I am showing result of button on first tab. i.e tab0 is active on tab0Event and on button click event too. And am able to change the tab events using tabHost.setOnTabChangedListener, but now what i further want is, say suppose i click on button so now button view is displaying(tab0 is active) but again if i click on tab0, tab0 activity should be displayed.
I tried many solutions for clicking on tab, one is
getTabWidget().getChildAt(getTabHost().getCurrentTab()).setOnClickListener
(new View.OnClickListener() {
#Override public void onClick(View v) {
System.out.println(getTabHost().getCurrentTab());
} });
But when i used this code with tabChnageListner, tab change not working and i got very unexpected results.
Would you please suggest solution for my problem.
Thanks.
code that is working for tab changed is as: (working fine for tab change, need to add Tab Onclick in it)
public class TabLayoutUsingTabChangeEventActivity extends TabActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost);
final TabHost.TabSpec sp1 = tabHost.newTabSpec("TAB1");
TabHost.TabSpec sp2 = tabHost.newTabSpec("TAB2");
//Creating First Tab
Intent intent1 = new Intent(this, Tab1Activity.class);
sp1.setIndicator("TAB1").setContent(intent1);
tabHost.addTab(sp1);
//Creating Second Tab
Intent intent2 = new Intent(this, Tab2Activity.class);
sp2.setIndicator("TAB2").setContent(intent2);
tabHost.addTab(sp2);
//Tab Changed Event
tabHost.setOnTabChangedListener(new OnTabChangeListener(){
#Override
public void onTabChanged(String tabId) {
Log.i("TabId :", tabId);
if(tabId.equals("TAB2")){
Log.i("TAB1", "TAB1 Changed");
Intent intent1 = new Intent().setClass(getApplicationContext(), Tab1Activity.class);
sp1.setIndicator("TAB1").setContent(intent1);
tabHost.setCurrentTab(0);
}
}
});
Button addNewButton = (Button)findViewById(R.id.add_new_ticket_btn);
addNewButton.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
Intent in = new Intent().setClass(getApplicationContext(), AddNewTicketActivity.class);
sp1.setContent(in);
tabHost.setCurrentTab(0);
//startActivity(in);
}
});
}
}
You can implement this listener:
host.setOnTabChangedListener(new OnTabChangeListener()
{
#Override
public void onTabChanged(String tabId)
{
if (getTabHost().getCurrentTabTag().equals("tab0"))
{
host.getCurrentTabView().setOnTouchListener(
new OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
if (getTabHost().getCurrentTabTag().equals("tab0")
{
getTabHost().setCurrentTabByTag("tab1");
getTabHost().setCurrentTabByTag("tab0");
}
return false;
}
return false;
}
});
}
}
});
Also when you add tabs set tag for every tab:
host.addTab(host.newTabSpec("tab0"));
host.addTab(host.newTabSpec("tab1"));
You can used Fragment to layout
You cant. Views in TabWidget already have onClickListener and it is required fo normal workflow. If you remove it you will break TabWidget's logic.
When you set your onClickListener you remove previuos onClickListener and you break TabWidget logic.
Usually in such cases compound click listener is created (a click listener which handles click event and calls another click listener). But not in your case because there is no way to get old click listener because View doesn't have getOnClickListener method.
This is TabWidget source code. All related values are private... so we can't fix anithing from this side.
The only way to achieve your goal is a hack with Reflections because they allows to read private vars. So before set View's new onlick listener you should get old one (using Reflections), then create compound onClickListener which will do your event handling code and then call old onClickListener. Set compound click listener to the View.