Question

I'm new to Android and therefore faced such problem.

How can I change layout from: enter image description here

To: enter image description here

XML fragment_main:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.snbgearassistant.MainActivity$PlaceholderFragment" >


<TextView
    android:id="@+id/section_label"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

</RelativeLayout>

So I need these tabs having grid layout with different content.

Was it helpful?

Solution

You must use a GridView inside the ViewPager. So, in your MainActivity, you would have this layout.

Create the activity_main.xml layout

This is the main layout. Everything will live inside of it, including your fragments and tabs.

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.myapp.gridview.MainActivity" />

Create your MainActivity.java class

public class MainActivity extends ActionBarActivity implements ActionBar.TabListener 
{

    SectionsPagerAdapter mSectionsPagerAdapter;

    /**
     * The {@link ViewPager} that will host the section contents.
     */
    ViewPager mViewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);

        // Here we load the xml layout we created above
        setContentView(R.layout.activity_main);

        // Set up the action bar.
        final ActionBar actionBar = getSupportActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        // Create the adapter that will return a fragment for each of the three
        // primary sections of the activity.
        mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);

        // When swiping between different sections, select the corresponding
        // tab. We can also use ActionBar.Tab#select() to do this if we have
        // a reference to the Tab.
        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() 
        {
            @Override
            public void onPageSelected(int position) 
            {
                actionBar.setSelectedNavigationItem(position);
            }
        });

        // For each of the sections in the app, add a tab to the action bar.
        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) 
        {
            // Create a tab with text corresponding to the page title defined by
            // the adapter. Also specify this Activity object, which implements
            // the TabListener interface, as the callback (listener) for when
            // this tab is selected.
            actionBar.addTab(
                    actionBar.newTab()
                            .setText(mSectionsPagerAdapter.getPageTitle(i))
                            .setTabListener(this));
        }
    }


    @Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) 
    {
        // When the given tab is selected, switch to the corresponding page in
        // the ViewPager.
        mViewPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) 
    {

    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) 
    {

    }

    /**
     * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
     * one of the sections/tabs/pages.
     */
    public class SectionsPagerAdapter extends FragmentPagerAdapter
    {

        public SectionsPagerAdapter(FragmentManager fm) 
        {
            super(fm);
        }

        @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).
            return new PlaceholderFragment();
        }

        @Override
        public int getCount() 
        {
            // Show 3 total pages.
            return 3;
        }

        @Override
        public CharSequence getPageTitle(int position) 
        {
            Locale l = Locale.getDefault();
            switch (position) 
            {
                case 0:
                    return getString(R.string.title_section1).toUpperCase(l);
                case 1:
                    return getString(R.string.title_section2).toUpperCase(l);
                case 2:
                    return getString(R.string.title_section3).toUpperCase(l);
            }
            return null;
        }
    }
}

Don't forget to create your strings for these R.string.title_section1, ... strings on your code, or you will have an error.

Now we must create a layout for the fragment (the page that will be displayed inside the tab), and it must contain a GridView.

Create a fragment_main.xml layout

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <GridView
        android:id="@+id/gridview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:verticalSpacing="0dp"
        android:horizontalSpacing="0dp"
        android:stretchMode="columnWidth"
        android:numColumns="2" />
</FrameLayout>

Now let's define the fragment class that will take care of inflating this layout and handling the views.

Create a fragment to inflate the GridView layout: PlaceHolderFragment.java

/**
 * A placeholder fragment containing a the gridview
 */
public class PlaceholderFragment extends Fragment 
{
    /**
     * The fragment argument representing the section number for this
     * fragment.
     */
    private static final String ARG_SECTION_NUMBER = "section_number";

    public PlaceholderFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);

        // Here we inflate the layout we created above
        GridView gridView = (GridView) rootView.findViewById(R.id.gridview);
        gridView.setAdapter(new MyAdapter(MainActivity.this.getApplicationContext()));

        return rootView;
    }
}

Now we must create an adapter class to handle each item of the GridView, this way you can manage the behavior of each one.

Create the Adapter to support the GridView items: MyAdapter.java

As you can see here, we are adding some items to the GridView by adding them to an ArrayList of the type Item defined in the end of the adapter class.

private class MyAdapter extends BaseAdapter
{
        private List<Item> items = new ArrayList<Item>();
        private LayoutInflater inflater;

        public MyAdapter(Context context)
        {
            inflater = LayoutInflater.from(context);

            items.add(new Item("Image 1", Color.GREEN));
            items.add(new Item("Image 2", Color.RED));
            items.add(new Item("Image 3", Color.BLUE));
            items.add(new Item("Image 4", Color.GRAY));
            items.add(new Item("Image 5", Color.YELLOW));
        }

        @Override
        public int getCount() {
            return items.size();
        }

        @Override
        public Object getItem(int i)
        {
            return items.get(i);
        }

        @Override
        public long getItemId(int i)
        {
            return items.get(i).colorId;
        }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup)
        {
            View v = view;
            ImageView picture;
            TextView name;

            if(v == null)
            {
                v = inflater.inflate(R.layout.gridview_item, viewGroup, false);
                v.setTag(R.id.picture, v.findViewById(R.id.picture));
                v.setTag(R.id.text, v.findViewById(R.id.text));
            }

            picture = (ImageView)v.getTag(R.id.picture);
            name = (TextView)v.getTag(R.id.text);

            Item item = (Item)getItem(i);

            picture.setBackgroundColor(item.colorId);
            name.setText(item.name);

            return v;
        }

        private class Item
        {
            final String name;
            final int colorId;

            Item(String name, int drawableId)
            {
                this.name = name;
                this.colorId = drawableId;
            }
        }
    }

Now to make the GridView items keep with the correct width, aligned side by side, we use a custom class to define the measured dimension.

Why this needs to be done? According to @kcoppock's answer:

Basically, in Android's ImageView class, there's no way to simply specify "hey, keep a square aspect ratio (width / height) for this view" unless you hard code width and height. You could do some manual adjustment of LayoutParams in the adapter's getView, but frankly, it's much simpler to let ImageView handle all the measurements, and just override the results to say "Whatever the width ends up being, make my height stay the same". You never have to think about it, it's always square, and it just works as expected. Basically this is the easiest way to keep the view square.

Create a class SquareImageView.java

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;

public class SquareImageView extends ImageView
{
    public SquareImageView(Context context)
    {
        super(context);
    }

    public SquareImageView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public SquareImageView(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); //Snap to width
    }
}

Now we must define the XML layout for the GridView items.

Create a XML layout gridview_item.xml

As you can see, here we add two items to the layout. One is a element of the type SquareImageView (the class we created above) and the TextView which is a label for each image.

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.myapp.gridview.SquareImageView
        android:id="@+id/picture"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        />
    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="15dp"
        android:paddingBottom="15dp"
        android:layout_gravity="bottom"
        android:textColor="@android:color/white"
        android:background="#55000000"
        />
</FrameLayout>

And here it is, I tested the code and this is the final result. Of course you would change those colors for your images, but this is the approach you should follow.

Note: To set images instead of colors to the GridView item, in your getView() method of the MyAdapter class use setImageResource(int) instead of setBackgroundColor(int).

enter image description here

OTHER TIPS

Answer Given By rogcg is very good and nice. But the Images for each fragment is same. I like to add some codes in the mainactivity which has viewpager.I think we can use fragment instead of activity, Here is the code.The same code as the Main Activity given by rogcg. Add these codes too.
In Layout for mainfragment add ActionBarlayout,toolbar and slidingtablayout
In Mainfragment,add 
  private List<Fragment> mFragments = new Vector<Fragment>();
 in oncreate(), create three fragments , 
    mFragments.add(new HomeFragment());
    mFragments.add(new Title1());
    mFragments.add(new Title2());
    mFragments.add(new Title3());
  in onCreateView(),add 
      mSectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager());
    mViewPager.setAdapter(mSectionsPagerAdapter);
    tabLayout = (SlidingTabLayout) v.findViewById(R.id.tabanim_tabs);
    tabLayout.setViewPager(mViewPager);
  in SectionPageAdapter class,add
    @Override
    public Fragment getItem(int position) {

        return mFragments.get(position+1);
    }

    @Override
    public int getCount() {

        return 3;

    }

    @Override
    public CharSequence getPageTitle(int position) {
      Locale l = Locale.getDefault();
        switch (position)
        {
            case 0:
                return getString(R.string.English).toUpperCase(l);
            case 1:
                return getString(R.string.Tamil).toUpperCase(l);
            case 2:
                return getString(R.string.Hindi).toUpperCase(l);
        }
        return null;

    }
 Now add any view in Title1() fragment as you usage and add any things in it I think this message was useful. please vote for me. Thank you.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top