Related
I am using design support to create tabs. I am also using ViewPager for swipable tabs.
Now, I don't know how to use only icons instead of texts in tabs. I tried finding out but didn't get any success.
My code:
Toolbar toolbar;
private TabLayout tabLayout;
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.pager);
setupViewPager(viewPager);
setupTablayout();
}
private void setupTablayout() {
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setupWithViewPager(viewPager);
}
class MyPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public MyPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFrag(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
mFragmentTitleList.get(position)
}
}
private void setupViewPager(ViewPager viewPager) {
MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager());
adapter.addFrag(new frag(), "CAT");
adapter.addFrag(new frag(), "DOG");
adapter.addFrag(new frag(), "BIRD");
viewPager.setAdapter(adapter);
}
One approach is setting the icons after TabLayout.setupWithViewPager() method.
mTabLayout.setupWithViewPager(mViewPager);
for (int i = 0; i < mTabLayout.getTabCount(); i++) {
mTabLayout.getTabAt(i).setIcon(R.drawable.your_icon);
}
The tutorial shown in the following link should cover what you want. https://github.com/codepath/android_guides/wiki/Google-Play-Style-Tabs-using-TabLayout#add-icons-to-tablayout
I copied the relevant section below.
Add Icons to TabLayout
Currently, the TabLayout class does not provide a clean abstraction model that allows for icons in your tab. There are many posted workarounds, one of which is to return a SpannableString, containing your icon in an ImageSpan, from your PagerAdapter's getPageTitle(position) method as shown in the code snippet below:
private int[] imageResId = {
R.drawable.ic_one,
R.drawable.ic_two,
R.drawable.ic_three
};
// ...
#Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
// return tabTitles[position];
Drawable image = context.getResources().getDrawable(imageResId[position]);
image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
SpannableString sb = new SpannableString(" ");
ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BOTTOM);
sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return sb;
}
By default, the tab created by TabLayout sets the textAllCaps property to be true, which prevents ImageSpans from being rendered. You can override this behavior by changing the tabTextAppearance property.
<style name="MyCustomTabLayout" parent="Widget.Design.TabLayout">
<item name="tabTextAppearance">#style/MyCustomTextAppearance</item>
</style>
<style name="MyCustomTextAppearance" parent="TextAppearance.Design.Tab">
<item name="textAllCaps">false</item>
</style>
In new version of TabLayout, google added TabItem which easily can add Icon through your XML with following code:
<android.support.design.widget.TabLayout
app:tabTextColor="#color/gray"
app:tabMode="fixed"
app:tabBackground="#color/red"
app:tabIndicatorHeight="4dp"
app:tabIndicatorColor="#color/purple"
app:tabPadding="2dp"
app:tabSelectedTextColor="#color/white"
app:tabMinWidth="64dp"
android:layout_height="wrap_content"
android:layout_width="match_parent">
<!--add height and width to TabItem -->
<android.support.design.widget.TabItem
android:text="#string/tab_text"/>
<android.support.design.widget.TabItem
android:icon="#drawable/ic_android"/>
</android.support.design.widget.TabLayout>
See more here.
try this
public class GlobalActivity extends AppCompatActivity {
Toolbar toolbar;
ViewPager viewPager;
TabLayout tabLayout;
ViewPagerAdapter adapter;
private int[] tabIcons = {
R.drawable.home_ic,
R.drawable.biz_ic,
R.drawable.network_ic,
R.drawable.offers_ic,
R.drawable.message_ic_b
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_global_hub);
tab();
}
public void tab(){
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout) findViewById(R.id.tablayout);
tabLayout.setupWithViewPager(viewPager);
setupTabIcons();
}
private void setupTabIcons() {
tabLayout.getTabAt(0).setIcon(tabIcons[0]);
tabLayout.getTabAt(1).setIcon(tabIcons[1]);
tabLayout.getTabAt(2).setIcon(tabIcons[2]);
tabLayout.getTabAt(3).setIcon(tabIcons[3]);
tabLayout.getTabAt(4).setIcon(tabIcons[4]);
}
public void setupViewPager(ViewPager viewPager){
adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFrag(new GlHubFragment(),"HOME");
adapter.addFrag(new BizForumFragment(), "BIZ FORUM");
adapter.addFrag(new NetworkFragment(), "NETWORK");
adapter.addFrag(new MessagesFragment(), "MESSAGEs");
adapter.addFrag(new OfferFragmentActivity(), "OFFER");
viewPager.setAdapter(adapter);
}
public class ViewPagerAdapter extends FragmentPagerAdapter{
private final List<Fragment> mfragmentlist =new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return mfragmentlist.get(position);
}
#Override
public int getCount() {
return mfragmentlist.size();
}
public void addFrag(Fragment fragment,String title){
mfragmentlist.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position){
return mFragmentTitleList.get(position);
}
}
}
In TabLayout, setting icon is easy:
getPageTitle(position) should return null (if you don't want title to show).
Next :
tabLayout.getTabAt(0).setIcon(resId);
tabLayout.getTabAt(1).setIcon(resId);
......
None of these methods are elegant when using TabLayout as the ViewPager "decor" scenario. TabLayout Documentation Here is a simple extension of TabLayout and PagerAdapter that provides a simple drop in replacement for TabLayout that should be able to be used in either scenario without manually adding icons outside of the TabLayout class and following the usage of PagerAdapter to get the tab information.
/**
* Created by JDL on 1/18/2017.
*/
public class TabLayoutExt extends TabLayout {
protected ViewPager mViewPager;
public abstract static class TabLayoutViewPagerAdapter extends PagerAdapter {
public TabLayoutViewPagerAdapter() {
}
/**
* This method may be called by the TabLayout to obtain an icon drawable
* to for the specified tab. This method may return null
* indicating no tab icon for this page. The default implementation returns
* null.
*
* #param position The position of the title requested
* #return A drawable icon for the requested page
*/
public Drawable getPageIcon(Context context, int position) {
return null;
}
}
public TabLayoutExt(Context context) {
super(context);
}
public TabLayoutExt(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TabLayoutExt(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onAttachedToWindow() {
//Cover the implicit setup in TabLayout
if (mViewPager == null) {
final ViewParent vp = getParent();
if (vp instanceof ViewPager) {
mViewPager = (ViewPager)vp;
}
}
super.onAttachedToWindow();
}
public void addTab(#NonNull Tab tab, int position, boolean setSelected) {
if (mViewPager != null && mViewPager.getAdapter() instanceof TabLayoutViewPagerAdapter) {
Drawable icon = ((TabLayoutViewPagerAdapter) mViewPager.getAdapter()).getPageIcon(getContext(),position);
tab.setIcon(icon);
}
super.addTab(tab,position,setSelected);
}
#Override
public void setupWithViewPager(#Nullable ViewPager viewPager, boolean autoRefresh) {
mViewPager = viewPager;
super.setupWithViewPager(viewPager, autoRefresh);
}
}
So all that needs be done is extend TabLayoutViewPagerAdapter instead of PageAdapter and implement getPageIcon(Context,int) instead of or in addition to title. The drop in TabLayoutExt in your XML file, instead of the normal TabLayout. This could be extended for further modifying the tab, either with a custom view instead or something else.
With the TabLayout provided by the Material Components Library you can use:
the method setIcon to define the resourceId
the method setTabLabelVisibility to set the TAB_LABEL_VISIBILITY_UNLABELED.
Something like:
for (int i=0;i<tabLayout.getTabCount();i++){
tabLayout.getTabAt(i).setIcon(iconResId);
tabLayout.getTabAt(i).
setTabLabelVisibility(TabLayout.TAB_LABEL_VISIBILITY_UNLABELED);
}
The easiest way I've found to use icons is to use Tablayout.Tab.setIcon(drawable). This also makes it easy to highlight the selected icon. If you want to do this, follow these steps.
Step 1.
Add your images to the res.mipmap folders. (mipmap-mdpi, hdpi etc.) Judging by the other answers here it's also fine to put then in the res.drawable folders.
Step 2.
Call setIcon on all your tabs after setting up your TabLayout and ViewPager. I did this in my AdapterTabs to keep the Activity tidy.
So in your activity do this:
tablayout = (TabLayout) findViewById(R.id.tab_layout);
viewPager = (ViewPager) findViewById(R.id.viewPager);
adapterTabs = new AdapterTabs(this, getSupportFragmentManager(), fragments, tablayout, viewPager);
viewPager.setAdapter(adapterTabs);
tablayout.setupWithViewPager(viewPager);
adapterTabs.setTabIcons();
and in your AdapterTabs, which should extend FragmentPagerAdapter, put your setTabIcons() method.
public void setTabTitlesToIcons() {
Drawable icon1 = context.getResources().getDrawable(R.mipmap.ic_1);
Drawable icon2 = context.getResources().getDrawable(R.mipmap.ic_2);
Drawable icon3 = context.getResources().getDrawable(R.mipmap.ic_3);
Drawable icon1Hilighted = context.getResources().getDrawable(R.mipmap.ic_1_selected);
Drawable icon2Hilighted = context.getResources().getDrawable(R.mipmap.ic_2_selected);
Drawable icon3Hilighted = context.getResources().getDrawable(R.mipmap.ic_3_selected);
icons.add(icon1);
icons.add(icon2);
icons.add(icon3);
iconsHilighted.add(icon1Hilighted);
iconsHilighted.add(icon2Hilighted);
iconsHilighted.add(icon3Hilighted);
for(int i = 0; i < icons.size(); i++) {
if(i == 0) {
//noinspection ConstantConditions
tabLayout.getTabAt(i).setIcon(iconsSelected.get(i));
}
else {
//noinspection ConstantConditions
tabLayout.getTabAt(i).setIcon(icons.get(i));
}
}
}
Make sure to store a reference to the two lists 'icons' and 'iconsHilighted'. You'll need them later. Also store a reference to the TabLayout and the ViewPager which you passed in from the activity.
Step 3.
Make sure AdapterTabs.getPageTitle() returns null.
At this point, if you run it you should see that the first icon is highlighted.
Step 4.
Implement ViewPager.OnPageChangeListener in AdapterTabs and add that listener to your viewPager
public AdapterTabs(Context context, FragmentManager fragmentManager, List<Fragment> fragments, TabLayout tabLayout, ViewPager viewPager) {
super(fragmentManager);
this.context = context;
this.tabLayout = tabLayout;
this.viewPager = viewPager;
this.viewPager.addOnPageChangeListener(this);
tabs.add(fragments.get(0));
tabs.add(fragments.get(1));
tabs.add(fragments.get(2));
}
Step 5.
Update the icons in the tabs in the onPageSelected callback in your AdapterTabs.
#Override
public void onPageSelected(int position) {
for (int i = 0; i < tabs.size(); i++) {
if(i == position) {
//noinspection ConstantConditions
tabLayout.getTabAt(i).setIcon(iconsSelected.get(i));
}
else {
//noinspection ConstantConditions
tabLayout.getTabAt(i).setIcon(icons.get(i));
}
}
}
Now you should see the hilighted icon being updated when you change tabs.
Try this this will definitely work .
private TabLayout tabLayout;
private ViewPager viewPager;
private int[] tabIcons = {
R.drawable.single,
R.drawable.multiple};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contact_picker);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle("Choose contact");
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
tab();
}
public void tab(){
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
setupTabIcons();
}
private void setupTabIcons() {
tabLayout.getTabAt(0).setIcon(tabIcons[0]);
tabLayout.getTabAt(1).setIcon(tabIcons[1]);
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new Login());
adapter.addFragment(new Register());
viewPager.setAdapter(adapter);
}
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment) {
mFragmentList.add(fragment);
}
}
As mentioned in the comments, defining the icons in the TabLayout does not work when using a PagerAdapter. For those using Kotlin, one workaround is to create an extension function like this:
fun TabLayout.setupWithViewPagerAndKeepIcons(viewPager : ViewPager?) {
val icons = mutableListOf<Drawable?>()
repeat(tabCount) {
icons.add(getTabAt(it)?.icon)
}
setupWithViewPager(viewPager)
repeat(tabCount) {
getTabAt(it)?.setIcon(icons.get(it))
}
}
Then in the layout.xml add your icons to the TabLayout:
<com.google.android.material.tabs.TabLayout
android:id="#+id/tab_layout">
<com.google.android.material.tabs.TabItem
android:icon="#drawable/your_icon"/>
</com.google.android.material.tabs.TabLayout>
Finally, use the extension function to setup the TabLayout with a ViewPager.
tab_layout.setupWithViewPagerAndKeepIcons(view_pager)
the simplest way is create new table by setting Icon on tablayout. below code will create two tab with icon only. use this code on onCreate() method
tablayout = (TabLayout) findViewById(R.id.order_tablayout);
tablayout.addTab( tablayout.newTab().setIcon(getResources().getDrawable(R.mipmap.ic_shopping_cart_white_24dp)) );
tablayout.addTab( tablayout.newTab().setIcon(getResources().getDrawable(R.mipmap.ic_like2_fille_white_24dp)) );
Using a ViewPager. This is how I have a tab with an icon only and no text.
TabLayout tabs...
TabLayout.Tab tab = tabs.getTabAt(0);
tab.setText("");
tab.setIcon(R.drawable.yourIcon);
This may not be the best answer for all cases, but what I found did not solve my problem yet.
After having a look at Androids implementation of tabLayout.setupWithViewPager(ViewPager pager) I came up with a solution using just listeners.
The layout structure:
| LinearLayout (vertical)
|-- TabLayout (width: match_parent)
|---- TabItem (without text, just icons)
|---- TabItem
|---- ...
|-- ViewPager
Code for the both listeners:
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
pager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
tabLayout.setScrollPosition(position, positionOffset, false);
}
#Override
public void onPageSelected(int position) {
TabLayout.Tab tab = tabLayout.getTabAt(position);
if (tab != null) {
tab.select();
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
Have a look at the tabLayout.setScrollPosition call inside OnPageChangeListener.onPageScrolled for the more or less good moving of the indicator while scrolling.
This may not work if the TabLayout's width is not set to match_parent (or must be scrollable).
I have a tablayout with a viewpager2 and FragmentStateAdapter. I have 3 tabs, each with a NestedScrollView that wraps a Linear Layout:
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:id="#+id/scrollView"
android:focusableInTouchMode="true"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:descendantFocusability="blocksDescendants">
/* ... */
</LinearLayout>
</androidx.core.widget.NestedScrollView>
When I switch between the tabs in the tablayout, the scrollview does not start at the top. In the onViewCreated() method of each Fragment for the viewPager, I added the following lines, however the scrollview still does not scroll to the top, it starts where it was left off.
public static class MyFragment extends Fragment {
private NestedScrollView scrollView;
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
scrollView = view.findViewById(R.id.scrollView);
scrollView.smoothScrollTo(0, 0);
}
}
The solution from #star4z should work, but there is an easier option. What you could do instead, use FragmentPagerAdapter for this and set it's behavior to BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT.
Every time, you change your tab, onResume will be called and there you can call your scrollView.smoothScrollTo(0, 0);
public class MyAdapter extends FragmentPagerAdapter {
...
public MyAdapter(FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
...
}
And then in your Fragment:
public class MyFragment extends Fragment {
...
public void onResume() {
super.onResume();
scrollView.smoothScrollTo(0, 0);
}
...
}
onViewCreated is only called when the Fragments are first created. A ViewPager does not change the state of the Fragments. You can think of the hidden Fragments being stored, visible, to the sides of the currently visible Fragment.
I accomplished by setting up a callback when the TabLayout changes. The TabLayout is where the listener for this is. You can then have it call a callback method in your FragmentPagerAdapter. In each Fragment, you should implement a method that returns a callback. In the FragmentPagerAdapter, use the getItem(int position) to store the callback from the Fragment in a Map. The callback method in the adapter takes the position from the TabLayout
First, in your Fragments, give them a method that returns some kind of callback (I used a Runnable) that will be called from the adapter.
public class PlaceHolderFragment extends Fragment {
...
public Runnable getOnTabChangedListener() {
return new Runnable() {
#Override
public void run() {
scrollView.smoothScrollTo(0, 0);
}
};
}
...
}
Then, in your FragmentPagerAdapter (I called mine SectionsPagerAdapter), store the callbacks in a map in the getItem() method, and then add a custom callback.
public class SectionsPagerAdapter extends FragmentPagerAdapter {
...
HashMap<Integer, Runnable> tabChangedCallbacks = new HashMap<>();
...
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
PlaceholderFragment fragment = PlaceholderFragment.newInstance(position + 1);
tabChangedCallbacks.put(position, fragment.getOnTabChangedListener());
return fragment;
}
public void onTabChanged(int position) {
tabChangedCallbacks.get(position).run();
}
...
}
In your activity that contains the TabLayout, you will want to call addOnTabSelectedListener() on the TabLayout in the onCreate() method.
protected void onCreate(Bundle savedInstanceState) {
...
final SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
final ViewPager viewPager = findViewById(R.id.view_pager);
viewPager.setAdapter(sectionsPagerAdapter);
TabLayout tabs = findViewById(R.id.tabs);
tabs.setupWithViewPager(viewPager);
tabs.addOnTabSelectedListener(
new TabLayout.ViewPagerOnTabSelectedListener(viewPager) {
#Override
public void onTabSelected(TabLayout.Tab tab) {
super.onTabSelected(tab);
sectionsPagerAdapter.onTabChanged(tab.getPosition());
}
});
...
}
EDIT
The principle is the same, but for this to work using ViewPager2 and FragmentStateAdapter, you will need the follow changes:
The Fragment stays the same.
The adapter is the same, functionally, with some updated methods:
public class SectionsStateAdapter extends FragmentStateAdapter {
HashMap<Integer, Runnable> tabChangedCallbacks = new HashMap<>();
...
public void onTabChanged(int position) {
tabChangedCallbacks.get(position).run();
}
#NonNull
#Override
public Fragment createFragment(int position) {
PlaceholderFragment fragment = PlaceholderFragment.newInstance(position + 1);
tabChangedCallbacks.put(position, fragment.getOnTabChangedListener());
return fragment;
}
#Override
public int getItemCount() {
return 2;
}
...
}
The activity changes the most:
public class MainActivity extends AppCompatActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
final SectionsStateAdapter sectionsStateAdapter = new SectionsStateAdapter(this);
final ViewPager2 viewPager = findViewById(R.id.view_pager);
viewPager.setAdapter(sectionsStateAdapter);
TabLayout tabs = findViewById(R.id.tabs);
// connect the TabLayout to the ViewPager2
new TabLayoutMediator(tabs, viewPager, new TabLayoutMediator.TabConfigurationStrategy() {
#Override
public void onConfigureTab(#NonNull TabLayout.Tab tab, int position) {
// set tab text, etc
}
}).attach();
// set the change listener on the ViewPager2
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
#Override
public void onPageSelected(int position) {
super.onPageSelected(position);
sectionsStateAdapter.onTabChanged(position);
}
});
...
}
}
Note that the only real change is that the ViewPager2 doesn't need the TabLayout to handle the page change. You could still use TabLayout.addOnTabSelectedListener() if you wanted, but you would have to implement your own TabLayout.OnTabSelecterListener since TabLayout.ViewPagerOnTabSelectedListener doesn't work with ViewPager2.
For example:
tabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
sectionsStateAdapter.onTabChanged(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
I want this type of design ::
Here Is My design
My mainactivity.xml only contain a frameLayout which is Replaced by Selected Fragment from bottombar menu item.
It's code is here:
b = BottomBar.attach(this,savedInstanceState);
b.setItemsFromMenu(R.xml.menu_main, new OnMenuTabClickListener() {
#Override
public void onMenuTabSelected(#IdRes int menuItemId) {
if(menuItemId == R.id.BottomBarItemOne){
PeopleFragment p = new PeopleFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame,p).commit();
}
else if(menuItemId == R.id.BottomBarItemTwo){
LocationFragment l = new LocationFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame,l).commit();
}
else if(menuItemId == R.id.BottomBarItemThree){
HistoryFragment h = new HistoryFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame,h).commit();
}
else if(menuItemId == R.id.BottomBarItemFour){
LikesFragment li = new LikesFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame,li).commit();
}
}
Now I want to create a tabview in on one of the Fragment :
For that I implement toolbar,tablayout and viewpager in required fragment xml file.
I created a separate java file contain viewPagerAdapter class.
public class viewPagerAdapter extends FragmentPagerAdapter {
ArrayList<Fragment> fragments = new ArrayList<>(); // this line can cause crashes
ArrayList<String> tabTitles = new ArrayList<>();
public void addFragment(Fragment fragment,String tabTitle){
fragments.add(fragment); // this line can cause crashes
tabTitles.add(tabTitle);
}
public viewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments.size();
}
#Override
public CharSequence getPageTitle(int position) {
return tabTitles.get(position);
}
}
Now I want to add this code to implement tablayout ::
toolbar = (Toolbar) findViewById(R.id.toolBar);
setSupportActionBar(toolbar);
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
viewPager = (ViewPager) findViewById(R.id.viewPager);
viewPagerAdapter = new viewPagerAdapter(getSupportFragmentManager());
viewPagerAdapter.addFragment(new HomeFragment(),"Home"); // this line can cause crashes
viewPagerAdapter.addFragment(new MessageFragment(),"Message"); // this line can cause crashes
viewPagerAdapter.addFragment(new ContectFragment(),"Contect"); // this line can cause crashes
viewPager.setAdapter(viewPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
In Fragment's onCreate method Given below ::
public class HomeFragment extends Fragment {
public HomeFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TabLyout Code Here
return inflater.inflate(R.layout.fragment_home, container, false);
}
}
But Android Studio doesn't allow Tablayout Fragment code in Fragment.
What Can I do ?
How can I implement tablayout in one of the fragment?
Try the following approach :
Add this to your fragment layout as per your requirement.
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="50dp"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:tabIndicatorColor="#color/tab_indicator"
app:tabIndicatorHeight="2.5dp"
app:tabPaddingBottom="-1dp"
app:tabPaddingEnd="-1dp"
app:tabPaddingStart="-1dp"
app:tabPaddingTop="-1dp"
app:tabBackground="#color/white"/>
Create one model for your tabs which you want to show.
Now add the following code in your fragment:
this.navigationData = new ArrayList<>();
this.navigationData.add(new MainNavigationViewModel("TAB-1", R.drawable.TAB-1, R.drawable.TAB-1, true));
this.navigationData.add(new MainNavigationViewModel("TAB-2", R.drawable.TAB-2, R.drawable.TAB-2, false));
this.navigationData.add(new MainNavigationViewModel("TAB-3", R.drawable.TAB-3, R.drawable.TAB-23, false));
for (MainNavigationViewModel vm : this.navigationData) {
tabLayout.addTab(tabLayout.newTab().setCustomView(ViewHelper.buildTabWithText(getContext(), vm.getText(), vm.getIsSelected())));
}
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
adapter = new MainFragmentPagerAdapter(getChildFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(adapter);
Now create FragmentPagerAdapter (New class) like this.
public class MainFragmentPagerAdapter extends FragmentPagerAdapter {
private interface FragmentFactory {
Fragment create();
}
private static final FragmentFactory[] fragments = new FragmentFactory[] {
() -> LiveFeedFragment.getInstance(),
() -> GroupsFragment.getInstance(),
() -> NewsFragment.getInstance()
};
public MainFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
return fragments[position].create();
}
#Override
public int getCount() {
return fragments.length;
}
}
And access the fragment like this way.
I have been searching and coding for 3 days now on this problem, no result :(
I made a camera overlay which the code is here + the Accelerometer
public class CameraActivity extends Activity implements SurfaceHolder.Callback, SensorEventListener {
Camera camera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
boolean previewing = false;
LayoutInflater controlInflater = null;
static String TAG = CameraActivity.class.getSimpleName();
// Accelerometer
private SensorManager mSensorManager;
private Sensor mAccelerometer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.surface_view);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
surfaceView = (SurfaceView) findViewById(R.id.camerapreview);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
controlInflater = LayoutInflater.from(getBaseContext());
View viewControl = controlInflater.inflate(R.layout.camera_control,
null);
LayoutParams layoutParamsControl = new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
this.addContentView(viewControl, layoutParamsControl);
// Accelerometer
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mAccelerometer = mSensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, mAccelerometer,
SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
#Override
public void onSensorChanged(SensorEvent event) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
if (previewing) {
camera.stopPreview();
previewing = false;
}
if (camera != null) {
try {
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
previewing = true;
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview();
camera.release();
camera = null;
previewing = false;
}
}
Then in the camera_control.xml I have this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_holder"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#android:color/transparent"
android:gravity="bottom" >
<ImageView
android:id="#+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/camera_red_button"
android:layout_alignLeft="#+id/camera_back_button"
android:layout_marginBottom="27dp"
android:src="#drawable/camera_accelerometer_red" />
</RelativeLayout>
and in the surface_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/camerapreview_holder"
>
<SurfaceView
android:id="#+id/camerapreview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
The Image View is a image for spirit level.
The idea is user needs to level the camera before she takes a photo. I have cleared all the un-nessessery code. The above code are working code.
Question:
I need to make a ball for the spirit level. it doesnt need to be the smoothest spirit level. If I can find the way to confine the ball within the spirit level and move it based on the Accelerometer results I will be as happy as Larry :)/
If someone please put me in the right direction regarding these 3 things:
confining the animation within an area
confinement area to be Circle, how to make it
Thanks in advance.
H.
Ok I have got the answer. Hope it can help someone. You need to use calculate the distance from the middle to the corner (radius) the offset the corners.
Also I have change the Accelerometor to Orientation Sensor which then I can get the 3d rotation of the phone in the X and Y Axis.
The following code is working code and I tested them. I am using the Android 2.3.3+
The ball movement is not very smooth as this is not the purpose of the application.
I think in order to smooth the movement you might need to add the timer and collision detection to it too. Please check the android sample.
I haven't refactor the code too yet. So this is not a production level code :)
Codes:
public class CameraActivity extends Activity implements SurfaceHolder.Callback,
SensorEventListener {
// Accelerometer
private SensorManager mSensorManager;
private Sensor mAccelerometer;
/** Called when the activity is first created. */
public static float x;
public static float y;
FrameLayout layout_holder;
FrameLayout ball_holder;
// private float hOriginSize;
float halfOfWidth;
int centerYOnImage;
private Sensor mOrientation;
// float viewInset = 14.0f; // I remove this simply to make the code cleaner. I used this to calculate the radius and the offset later on
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.surface_view);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
surfaceView = (SurfaceView) findViewById(R.id.camerapreview);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
controlInflater = LayoutInflater.from(getBaseContext());
View viewControl = controlInflater.inflate(R.layout.camera_control,
null);
LayoutParams layoutParamsControl = new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
this.addContentView(viewControl, layoutParamsControl);
// Accelerometer
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mOrientation = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
mSensorManager.registerListener(this, mAccelerometer,
SensorManager.SENSOR_DELAY_NORMAL);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.ball);
CustomDrawableView mCustomDrawableView = new CustomDrawableView(this,
bitmap);
ball_holder = (FrameLayout) findViewById(R.id.ball_holder);
ball_holder.addView(mCustomDrawableView);
halfOfWidth = 40; // You can calculate this, I just put this so I can test it. This is the half of the width of target image - attached in the question
centerYOnImage = 40; // Not important :)
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
// This method will update the UI on new sensor events
public void onSensorChanged(SensorEvent event) {
// float azimuth_angle = event.values[0];
x = event.values[1];
y = event.values[2];
// FIXME: Fine tune this for the image taking part
float ratio = 70.0f / 25.0f;
x = x * ratio;
y = y * ratio;
Log.d(TAG, "x and y: " + x + " " + y);
float maxDistance = 35; // To calculate this halfOfWidth - viewInset;
// to calculate between 2 distances
float distance = (float) Math.sqrt(((x) * (x)) + ((y) * (y)));
if (distance > maxDistance) {
float angle = (float) Math.atan2(x, y);
/ Get new point on the edge of the circle
y = (float) (Math.cos(angle) * maxDistance);
x = (float) (Math.sin(angle) * maxDistance);
}
x = x + 40; // 40 is the half od the distance of the full width
y = (y * -1.0f) + 40; // -1.0f is so orientation works like the actual spirit level
canUserTakePhoto(distance);
}
// Change the background
public void canUserTakePhoto(float treshold) {
if (treshold > 10) {
// Not Yet
} else {
// take it
}
}
#Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, mOrientation,
SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
public class CustomDrawableView extends ImageView {
Bitmap b;
public CustomDrawableView(Context context, Bitmap bitmap) {
super(context);
this.b = bitmap;
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(this.b, x, y, null);
invalidate();
}
}
#Override
public void onDestroy() // main thread stopped
{
super.onDestroy();
// wait for threads to exit before clearing app
System.runFinalizersOnExit(true);
// remove app from memory
android.os.Process.killProcess(android.os.Process.myPid());
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
if (previewing) {
camera.stopPreview();
previewing = false;
}
if (camera != null) {
try {
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
previewing = true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
camera = Camera.open();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
camera.stopPreview();
camera.release();
camera = null;
previewing = false;
}
}
Cheers.
I have an openCV application program working, but need to add buttons etc. to the layout. So basically I want to display the opencv camera view on a surfaceView and the add the other stuff underneath.
I've been searching the internet and forums for a while, only seeing the guy with a opencv facial detection application also wanting to add a custom layout... no solution.
I am really desperate for a solution so would hugely appreciate help. For this purpose I used the OpenCV sample 3 application (as a simple example) and tried to bind to a surfaceview on a simple custom layout. I managed it in a normal Camera application, but struggling quite a bit with the opencv example.
So this is the code that I have for the Sample3Native.java, Sample3View.java and SampleViewBase.java (as in example) files respectively:
public class Sample3Native extends Activity {
private Sample3View mView;
private BaseLoaderCallback mOpenCVCallBack = new BaseLoaderCallback(this) {
#Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
// Load native library after(!) OpenCV initialization
System.loadLibrary("native_sample");
// Create and set View
mView = new Sample3View(mAppContext);
setContentView(R.layout.main);
//setContentView(mView);
// Check native OpenCV camera
mView.openCamera();
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
//constructor
public Sample3Native() {}
#Override
protected void onPause() {
super.onPause();
if (null != mView)
mView.releaseCamera();
}
#Override
protected void onResume() {
super.onResume();
if((null != mView) && !mView.openCamera() ) {
AlertDialog ad = new AlertDialog.Builder(this).create();
ad.setCancelable(false); // This blocks the 'BACK' button
ad.setMessage("Fatal error: can't open camera!");
ad.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
finish();
}
});
ad.show();
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_2, this, mOpenCVCallBack);
}
}
class Sample3View extends SampleViewBase {
private int mFrameSize;
private Bitmap mBitmap;
private int[] mRGBA;
public Sample3View(Context context) {
super(context);
}
#Override
protected void onPreviewStarted(int previewWidtd, int previewHeight) {
mFrameSize = previewWidtd * previewHeight;
mRGBA = new int[mFrameSize];
mBitmap = Bitmap.createBitmap(previewWidtd, previewHeight, Bitmap.Config.ARGB_8888);
}
#Override
protected void onPreviewStopped() {
if(mBitmap != null) {
mBitmap.recycle();
mBitmap = null;
}
mRGBA = null;
}
#Override
protected Bitmap processFrame(byte[] data) {
int[] rgba = mRGBA;
FindFeatures(getFrameWidth(), getFrameHeight(), data, rgba);
Bitmap bmp = mBitmap;
bmp.setPixels(rgba, 0, getFrameWidth(), 0, 0, getFrameWidth(), getFrameHeight());
return bmp;
}
public native void FindFeatures(int width, int height, byte yuv[], int[] rgba);
}
public abstract class SampleViewBase extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private Camera mCamera;
private SurfaceHolder mHolder;
private SurfaceView mViewer;
private int mFrameWidth;
private int mFrameHeight;
private byte[] mFrame;
private boolean mThreadRun;
private byte[] mBuffer;
public SampleViewBase(Context context) {
super(context);
mViewer = (SurfaceView)this.findViewById(R.id.camera_view);
mHolder = mViewer.getHolder();
mHolder.addCallback(this);
}
public int getFrameWidth() {
return mFrameWidth;
}
public int getFrameHeight() {
return mFrameHeight;
}
public boolean openCamera() {
releaseCamera();
mCamera = Camera.open();
if(mCamera == null)
return false;
mCamera.setPreviewCallbackWithBuffer(new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
synchronized (SampleViewBase.this) {
System.arraycopy(data, 0, mFrame, 0, data.length);
SampleViewBase.this.notify();
}
camera.addCallbackBuffer(mBuffer);
}
});
return true;
}
public void releaseCamera() {
mThreadRun = false;
synchronized (this) {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
onPreviewStopped();
}
public void setupCamera(SurfaceHolder holder,int width, int height) {
synchronized (this) {
if (mCamera != null) {
Camera.Parameters params = mCamera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
mFrameWidth = width;
mFrameHeight = height;
// selecting optimal camera preview size
{
int minDiff = Integer.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - height) < minDiff) {
mFrameWidth = size.width;
mFrameHeight = size.height;
minDiff = Math.abs(size.height - height);
}
}
}
params.setPreviewSize(getFrameWidth(), getFrameHeight());
List<String> FocusModes = params.getSupportedFocusModes();
if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
{
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
}
mCamera.setParameters(params);
/* Now allocate the buffer */
params = mCamera.getParameters();
int size = params.getPreviewSize().width * params.getPreviewSize().height;
size = size * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
mBuffer = new byte[size];
/* The buffer where the current frame will be copied */
mFrame = new byte [size];
mCamera.addCallbackBuffer(mBuffer);
try {
mCamera.setPreviewDisplay(holder);
//mCamera.setPreviewDisplay(null);
} catch (IOException e) {}
/* Notify that the preview is about to be started and deliver preview size */
onPreviewStarted(params.getPreviewSize().width, params.getPreviewSize().height);
/* Now we can start a preview */
mCamera.startPreview();
}
}
}
public void surfaceChanged(SurfaceHolder _holder, int format, int width, int height) {
setupCamera(_holder,width, height);
}
public void surfaceCreated(SurfaceHolder holder) {
(new Thread(this)).start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
releaseCamera();
}
//abstract functions used by child class
protected abstract Bitmap processFrame(byte[] data);
protected abstract void onPreviewStarted(int previewWidtd, int previewHeight);
protected abstract void onPreviewStopped();
//================================
public void run() {
mThreadRun = true;
while (mThreadRun) {
Bitmap bmp = null;
synchronized (this) {
try {
this.wait();
bmp = processFrame(mFrame);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (bmp != null) {
Canvas canvas = mHolder.lockCanvas();
if (canvas != null) {
canvas.drawBitmap(bmp, (canvas.getWidth() - getFrameWidth()) / 2, (canvas.getHeight() - getFrameHeight()) / 2, null);
mHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
I know this must be a MAJOR drag to go through my code, but I really need the help. Or even if I could get a link to a working example of this type of implementation. Also, please just don't send me this link (it doesn't help me):openCV in custom applications
This is my acitivity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:opencv="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<org.opencv.android.JavaCameraView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone"
android:id="#+id/tutorial1_activity_java_surface_view"
opencv:show_fps="true"
opencv:camera_id="any" />
<org.opencv.android.NativeCameraView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone"
android:id="#+id/tutorial1_activity_native_surface_view"
opencv:show_fps="true"
opencv:camera_id="any" />
<Button
android:id="#+id/btnOK"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="105dp"
android:layout_marginTop="139dp"
android:onClick="OKClicked"
android:text="#string/OK" />
<TextView
android:id="#+id/txtDisp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/btnOK"
android:layout_alignBottom="#+id/btnOK"
android:layout_marginLeft="25dp"
android:layout_toRightOf="#+id/btnOK"
android:text="#string/app_name"
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
And these code must be edited to MainActivity.java class
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
if (mIsJavaCamera){
mOpenCvCameraView = (CameraBridgeViewBase)findViewById(R.id.tutorial1_activity_java_surface_view);
}else{
mOpenCvCameraView = (CameraBridgeViewBase)findViewById(R.id.tutorial1_activity_native_surface_view);
}
mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
ArrayList<View> views = new ArrayList<View>();
views.add(findViewById(R.id.btnOK));
views.add(findViewById(R.id.txtDisp));
mOpenCvCameraView.addTouchables(views);
}
public void OKClicked(View view){
TextView disp = (TextView)findViewById(R.id.txtDisp);
disp.setText("OK Clicked");
}
This code is modified to OpenCV Tutorial 1.
You will see a button and a TextView over the surfaceview. When you click OK button TextView will show "OK Clicked". This is working for me on Samsung Galaxy.