选项卡内的网格布局 [英] Grid layout within tabs

查看:32
本文介绍了选项卡内的网格布局的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 Android 新手,因此遇到了这样的问题.

如何更改布局:

到:

XML 片段主:

<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_horizo​​ntal_margin"android:paddingRight="@dimen/activity_horizo​​ntal_margin"android:paddingTop="@dimen/activity_vertical_margin"工具:context="com.example.snbgearassistant.MainActivity$PlaceholderFragment" ><文本视图android:id="@+id/section_label"android:layout_width="wrap_content"android:layout_height="wrap_content"/></相对布局>

所以我需要这些标签具有不同内容的网格布局.

解决方案

您必须在 ViewPager 中使用 GridView.因此,在您的 MainActivity 中,您将拥有此布局.

创建 activity_main.xml 布局

这是主要布局.一切都将存在于其中,包括您的片段和标签.

创建您的 MainActivity.java 类

公共类 MainActivity 扩展 ActionBarActivity 实现 ActionBar.TabListener{SectionsPagerAdapter mSectionsPagerAdapter;/*** 将承载部分内容的 {@link ViewPager}.*/ViewPager mViewPager;@覆盖protected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);//这里我们加载我们上面创建的xml布局setContentView(R.layout.activity_main);//设置操作栏.最终的 ActionBar actionBar = getSupportActionBar();actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);//创建适配器,它将为这三个中的每一个返回一个片段//活动的主要部分.mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());//使用部分适配器设置 ViewPager.mViewPager = (ViewPager) findViewById(R.id.pager);mViewPager.setAdapter(mSectionsPagerAdapter);//在不同部分之间滑动时,选择对应的//标签.我们也可以使用 ActionBar.Tab#select() 来做到这一点,如果我们有//对 Tab 的引用.mViewPager.setOnPageChangeListener(新 ViewPager.SimpleOnPageChangeListener(){@覆盖公共无效 onPageSelected(int 位置){actionBar.setSelectedNavigationItem(位置);}});//对于应用程序中的每个部分,将选项卡添加到操作栏.for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++){//创建一个选项卡,其文本对应于定义的页面标题//适配器.还要指定这个Activity对象,它实现//TabListener 接口,作为when的回调(监听器)//这个选项卡被选中.actionBar.addTab(actionBar.newTab().setText(mSectionsPagerAdapter.getPageTitle(i)).setTabListener(this));}}@覆盖公共无效 onTabSelected(ActionBar.Tab 选项卡,FragmentTransaction 片段事务){//当给定的选项卡被选中时,切换到对应的页面//ViewPager.mViewPager.setCurrentItem(tab.getPosition());}@覆盖公共无效 onTabUnselected(ActionBar.Tab 选项卡,FragmentTransaction 片段事务){}@覆盖公共无效 onTabReselected(ActionBar.Tab 选项卡,FragmentTransaction 片段事务){}/*** 一个 {@link FragmentPagerAdapter} 返回对应的片段* 部分/选项卡/页面之一.*/公共类 SectionsPagerAdapter 扩展 FragmentPagerAdapter{公共 SectionsPagerAdapter(FragmentManager fm){超级(调频);}@覆盖公共片段getItem(int位置){//调用 getItem 来实例化给定页面的片段.//返回一个 PlaceholderFragment(定义为下面的静态内部类).返回新的占位符片段();}@覆盖公共 int getCount(){//显示总共 3 页.返回 3;}@覆盖公共 CharSequence getPageTitle(int position){语言环境 l = Locale.getDefault();开关(位置){案例0:返回 getString(R.string.title_section1).toUpperCase(l);情况1:返回 getString(R.string.title_section2).toUpperCase(l);案例2:返回 getString(R.string.title_section3).toUpperCase(l);}返回空值;}}}

<块引用>

不要忘记在代码中为这些 R.string.title_section1, ... 字符串创建字符串,否则会出错.

现在我们必须为片段(将在选项卡中显示的页面)创建一个布局,并且它必须包含一个 GridView.

创建一个 fragment_main.xml 布局

<?xml version="1.0" encoding="utf-8"?><框架布局xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><网格视图android:id="@+id/gridview"android:layout_width="match_parent"android:layout_height="match_parent"android:verticalSpacing="0dp"android:horizo​​ntalSpacing="0dp"android:stretchMode="columnWidth"android:numColumns="2"/></框架布局>

现在让我们定义片段类,它将负责扩展此布局并处理视图.

创建一个片段来膨胀 GridView 布局:PlaceHolderFragment.java

/*** 一个包含gridview的占位符片段*/公共类 PlaceholderFragment 扩展 Fragment{/*** 片段参数表示此部分的编号* 片段.*/私有静态最终字符串 ARG_SECTION_NUMBER = "section_number";公共占位符片段(){}@覆盖public View onCreateView(LayoutInflater inflater, ViewGroup 容器, Bundle savedInstanceState){查看 rootView = inflater.inflate(R.layout.fragment_main, container, false);//这里我们对上面创建的布局进行膨胀GridView gridView = (GridView) rootView.findViewById(R.id.gridview);gridView.setAdapter(new MyAdapter(MainActivity.this.getApplicationContext()));返回根视图;}}

现在我们必须创建一个适配器类来处理GridView的每一项,这样你就可以管理每一项的行为.

创建支持 GridView 项的适配器:MyAdapter.java

正如您在此处看到的,我们将一些项目添加到 GridView,方法是将它们添加到适配器类末尾定义的 Item 类型的 ArrayList.

私有类 MyAdapter 扩展 BaseAdapter{私人清单<项目>项目 = 新的 ArrayList<项目>();私人 LayoutInflater 充气机;公共 MyAdapter(上下文上下文){充气机 = LayoutInflater.from(context);items.add(new Item("图片 1", Color.GREEN));items.add(new Item("Image 2", Color.RED));items.add(new Item("图片 3", Color.BLUE));items.add(new Item("图片 4", Color.GRAY));items.add(new Item("Image 5", Color.YELLOW));}@覆盖公共 int getCount() {返回项目.size();}@覆盖公共对象 getItem(int i){返回 items.get(i);}@覆盖公共长 getItemId(int i){返回 items.get(i).colorId;}@覆盖public View getView(int i, View view, ViewGroup viewGroup){视图 v = 视图;ImageView 图片;文本视图名称;如果(v == 空){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));}图片 = (ImageView)v.getTag(R.id.picture);名称 = (TextView)v.getTag(R.id.text);项目项目 = (项目)getItem(i);图片.setBackgroundColor(item.colorId);name.setText(item.name);返回 v;}私有类项目{最终字符串名称;最终 int colorId;项目(字符串名称,int drawableId){this.name = 名称;this.colorId = drawableId;}}}

现在为了使 GridView 项目保持正确的宽度,并排对齐,我们使用自定义类来定义测量尺寸.

为什么需要这样做?根据@kcoppock的回答:

<块引用>

基本上,在 Android 的 ImageView 类中,除非您硬编码宽度和高度,否则无法简单地指定嘿,保持此视图的正方形纵横比(宽度/高度)".您可以在适配器的 getView 中对 LayoutParams 进行一些手动调整,但坦率地说,让 ImageView 处理所有测量结果要简单得多,只需覆盖结果即可宽度最终是,让我的高度保持不变".您永远不必考虑它,它始终是方形的,并且可以按预期工作.基本上这是保持视图正方形的最简单方法.

创建一个类 SquareImageView.java

导入android.content.Context;导入android.util.AttributeSet;导入android.widget.ImageView;公共类 SquareImageView 扩展 ImageView{公共 SquareImageView(上下文上下文){超级(上下文);}公共 SquareImageView(上下文上下文,AttributeSet attrs){超级(上下文,属性);}公共 SquareImageView(上下文上下文,AttributeSet attrs,int defStyle){超级(上下文,属性,defStyle);}@覆盖受保护的无效onMeasure(int widthMeasureSpec,int heightMeasureSpec){super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth());//对齐宽度}}

现在我们必须为 GridView 项定义 XML 布局.

创建一个 XML 布局 gridview_item.xml

如您所见,这里我们在布局中添加了两个项目.一个是 SquareImageView 类型的元素(我们在上面创建的类)和 TextView,它是每个图像的标签.

<?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.SquareImageViewandroid:id="@+id/图片"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="centerCrop"/><文本视图android:id="@+id/文本"android:layout_width="match_parent"android:layout_height="wrap_content"安卓:paddingLeft="10dp"安卓:paddingRight="10dp"android:paddingTop="15dp"android:paddingBottom="15dp"机器人:layout_gravity="底部"android:textColor="@android:color/white"安卓:背景=#55000000"/></框架布局>

在这里,我测试了代码,这是最终结果.当然,您会更改图像的这些颜色,但这是您应该遵循的方法.

注意:要为 GridView 项设置图像而不是颜色,请在 MyAdapter<的 getView() 方法中/code> 类使用 setImageResource(int) 而不是 setBackgroundColor(int).

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

How can I change layout from:

To:

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.

解决方案

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).

这篇关于选项卡内的网格布局的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆