`
lobin
  • 浏览: 380041 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Android: 布局

 
阅读更多

布局

Android提供了大量的布局

 

Android中的Layout其实也是一个视图,它们是一些视图容器,都继承了ViewGroup这个抽象类,这是一个容器视图类,这个类继承了View类。

 

布局参数

Android中每种布局都有一个对应的布局参数LayoutParams。

 

线性布局

在线性布局中,所有控件按照排列方式依次排列。默认情况下,所有控件按照水平排列方式依次排列。可以通过setOrientation方法设置排列方式,即排列方向。如果指定为LinearLayout.VERTICAL,按照垂直排列方向依次排列。水平排列方式为LinearLayout.HORIZONTAL。

 

LinearLayout

在Android Studio下,有时候会遇到这种错误提示:“No orientation specified, and the default is horizontal. This is a common source of bugs when children are added dynamically.”

出现这种错误提示的原因是我们在编写布局文件时,我们编写了一个空的LinearLayout布局,如下,里边没有放置任何子视图,我们可能希望在代码中动态的添加子视图,对于这种情况,我们需要指定android:orientation参数显式的设置一个线性排列方向,如android:orientation="horizontal",或者android:orientation="vertical"。

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linear"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff">

</LinearLayout>

 

 

LinearLayoutCompat

 

ForegroundLinearLayout

 

相对布局

Android提供RelativeLayout相对布局。

RelativeLayout

 

 

android:layout_alignParentTop

android:layout_alignParentBottom

android:layout_alignParentLeft

android:layout_alignParentRight

 

在下面的布局例子中,布局中显示一个ImageView,并在布局的左上角显示一个TextView,在布局的右上角显示一个CheckBox。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="#ffffff"
    android:id="@+id/item"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="300px"
        android:textSize="18sp"
        android:scaleType="centerCrop"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:background="@android:color/transparent"
        android:textSize="18sp"
        android:gravity="center"
        android:text="  "/>


    <CheckBox
        android:id="@+id/radio_select_state"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="true"
        android:scaleX="0.8"
        android:scaleY="0.8"
        android:button="@null"
        android:background="@drawable/check_style"/>
</RelativeLayout>

 

 

FlowLayout

 

GridLayout

GridLayout是一种网格布局,或者说表格布局。 

 

GridLayout.LayoutParams

通过两个Spec参数来构造网格布局参数,一个是行规格,一个是列规格。

public LayoutParams(Spec rowSpec, Spec columnSpec) {
    this(DEFAULT_WIDTH, DEFAULT_HEIGHT,
            DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN,
            rowSpec, columnSpec);
}

默认构造网格布局参数的方法

public LayoutParams() {
    this(Spec.UNDEFINED, Spec.UNDEFINED);
}

通过另一个ViewGroup.LayoutParams布局参数来构造网格布局参数

public LayoutParams(ViewGroup.LayoutParams params) {
    super(params);
}

通过另一个MarginLayoutParams布局参数来构造网格布局参数

public LayoutParams(MarginLayoutParams params) {
    super(params);
}

通过另一个LayoutParams布局参数来构造网格布局参数   

public LayoutParams(LayoutParams source) {
    super(source);

    this.rowSpec = source.rowSpec;
    this.columnSpec = source.columnSpec;
}

通过上下文和属性集来构造网格布局参数

public LayoutParams(Context context, AttributeSet attrs) {
    super(context, attrs);
    reInitSuper(context, attrs);
    init(context, attrs);
}

 

 

GridLayout grid = view.findViewById(R.id.grid);

grid.setOrientation(GridLayout.HORIZONTAL);

grid.setColumnCount(4);

grid.setRowCount(5);

 

向GridLayout中添加子视图

 

for (int i = 0; i < 16; i++) {

    ImageView itemView = new ImageView(parent.getContext());

    itemView.setBackgroundColor(Color.RED);

    itemView.setImageResource(R.drawable.photo);

    itemView.setPadding(2, 0, 2, 0);

    itemView.setTag("useralbum");

 

    itemView.setOnClickListener(new View.OnClickListener() {

        @Override

        public void onClick(View v) {

            onItemSelectedListener.onItemSelected(v);

        }

    });

 

    GridLayout.LayoutParams itemViewLayoutParams =

            new GridLayout.LayoutParams(

                    GridLayout.spec(GridLayout.UNDEFINED, 1f),

                    GridLayout.spec(GridLayout.UNDEFINED, 1f));

    itemView.setLayoutParams(itemViewLayoutParams);

    

    grid.addView(itemView);

}

 

ConstraintLayout

 

CoordinatorLayout

 

FrameLayout

在调用FragmentContainerView的addView(@NonNull View child, int index, @Nullable ViewGroup.LayoutParams params)方法(这个方法继承至ViewGroup类)的时候,报了一个错误:IllegalStateException,提示java.lang.IllegalStateException: Views added to a FragmentContainerView must be associated with a Fragment. View app.at.NoScrollListView{d7ce44c V.ED.VC.. ......I. 0,0-0,0} is not associated with a Fragment.信息。

 

FragmentContainerView的这个addView方法(这个方法继承至ViewGroup类)会调用到FragmentContainerView的addView(@NonNull View child, int index, @Nullable ViewGroup.LayoutParams params)方法,其中有这么一段检查:

        if (FragmentManager.getViewFragment(child) == null) {
            throw new IllegalStateException("Views added to a FragmentContainerView must be"
                    + " associated with a Fragment. View " + child + " is not associated with a"
                    + " Fragment.");
        }

这里FragmentManager的getViewFragment方法如下:

    @Nullable
    static Fragment getViewFragment(@NonNull View view) {
        Object tag = view.getTag(R.id.fragment_container_view_tag);
        if (tag instanceof Fragment) {
            return (Fragment) tag;
        }
        return null;
    }

这里会检查加入的view的一个key为R.id.fragment_container_view_tag的tag,这个tag必须是一个Fragment实例。

 

不过我们在代码中不能直接使用R.id.fragment_container_view_tag这个id。

 

在调用FragmentTransaction的add(@IdRes int containerViewId,@NonNull androidx.fragment.app.Fragment fragment)方法的时候,报了一个错误:IllegalStateException,提示java.lang.IllegalArgumentException: Can't add fragment Fragment{ea2c505} (b905f807-04f2-4679-8a74-9b8d72b53151) with tag null to container view with no id信息

 

 

FragmentTransaction的这个add方法会调用到FragmentTransaction的doAddOp方法,其中有这么一段检查:

            if (containerViewId == View.NO_ID) {
                throw new IllegalArgumentException("Can't add fragment "
                        + fragment + " with tag " + tag + " to container view with no id");
            }

即这里的FragmentContainerView必须要指定一个id,或者如果这个FragmentContainerView是在代码中直接创建的话,需要调用setId方法指定一个id,如fragmentContainerView.setId(R.id.fragment_container_view)。

 

在调用FragmentTransaction的add(@IdRes int containerViewId,@NonNull androidx.fragment.app.Fragment fragment)方法的时候,报了一个错误:IllegalStateException,提示java.lang.IllegalStateException: Fragment must be a public static class to be  properly recreated from instance state.信息

 

FragmentTransaction的这个add方法会调用到FragmentTransaction的doAddOp方法,其中有这么一段检查:

        final Class<?> fragmentClass = fragment.getClass();
        final int modifiers = fragmentClass.getModifiers();
        if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
                || (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
            throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName()
                    + " must be a public static class to be  properly recreated from"
                    + " instance state.");
        }

即传入的这个Fragment对象类必须满足:

1、不可以是匿名类

2、必须是public类

3、必须是静态类或者成员类

 

 

 

ScrimInsetsFrameLayout

 

ContentFrameLayout

 

TabLayout

 

TextInputLayout

 

DrawerLayout

 

FitWindowsLinearLayout

 

FitWindowsFrameLayout

 

ButtonBarLayout

 

BaselineLayout

 

AppBarLayout

 

ActionBarOverlayLayout

 

CollapsingToolbarLayout

 

CircularRevealLinearLayout

 

CircularRevealRelativeLayout

 

CircularRevealGridLayout

 

CircularRevealFrameLayout

 

CircularRevealCoordinatorLayout

 

SnackbarLayout

 

SnackbarContentLayout

 

 

SnackbarBaseLayout

 

AlertDialogLayout

 

MotionLayout

 

布局管理

 

布局管理器

 

布局参数

 

选项卡

Android提供了多种视图组件来实现选项卡。

 

TabLayout

 

TabRippleColor

默认情况下,点击选择一个选项时,会有波纹效果。

如果想要去掉这个效果的话,可以设置为null。

tabLayout.setTabRippleColor(null);

 

SelectedTabIndicator

 

TabLayout当前选项下面有一条下划线的指示效果,这个效果就是一个Indicator,也称为selection indicator,默认情况下就是选项卡下面有一条下划线。这个Indicator是一个Drawable,可以看TabLayout的Drawable tabSelectedIndicator。这个Indicator也是有高的。

 

tabLayout.setSelectedTabIndicator(R.drawable.tab_indicator);

在res/drawable下新建一个tab_indicator.xml文件

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:width="6dp"
        android:height="6dp"
        android:gravity="center" android:bottom="6dp">
        <shape>
            <corners android:radius="3dp"/>
        </shape>
    </item>
</layer-list>

这里我们想让Indicator水平居中,但如果设置为android:gravity="center_horizontal"的话,又没有效果,Indicator都显示不出来。设置为android:gravity="center"是可以的,它可以让Indicator水平垂直都居中,不过Indicator只显示了上面一半,下面一半没有显示出来,垂直居中感觉是以底部为基准进行垂直居中。这里设置android:bottom="6dp",在底部留出相应的内边界空间。

还有一种写法

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:gravity="center" android:bottom="6dp">
        <shape android:shape="rectangle">
            <solid android:color="@color/green"/>
            <corners android:bottomLeftRadius="3dp"
                android:bottomRightRadius="3dp"
                android:topLeftRadius="3dp"
                android:topRightRadius="3dp"/>
            <size android:height="6dp" android:width="6dp"/>
        </shape>
    </item>
</layer-list>

 

例子

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:width="20dp"
        android:height="5dp"
        android:gravity="center" android:bottom="5dp">
        <shape>
            <corners android:radius="5dp" />
        </shape>
    </item>
</layer-list>

 

 

尝试设置Indicator为一个图标是没有效果的。

tabLayout.setSelectedTabIndicator(R.drawable.toolbar_selected_normal);

可能反而去掉了默认的下划线指示效果。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:width="20dp"
        android:height="20dp"
        android:gravity="center"
        android:drawable="@drawable/toolbar_selected_normal"
        android:bottom="20dp">
        <shape/>
    </item>
</layer-list>

 

 

有时候我们不想要有这个指示效果,想要去掉这条下划线。

可以通过setSelectedTabIndicator设置这个Indicator,如果指定为null,就不会有这个了。也可以将Indicator的高设置为0。调用setSelectedTabIndicatorHeight方法可以指定高。

 

长按事件

        tabLayout.getTabAt(0).view.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                Log.d(getClass().getName(), "long click");

                return true;
            }
        });

 

 

 

分享到:
评论

相关推荐

    Android :布局与国际化

    使用合适的布局方法(不用约束布局),实现如下界面。并实软件国际化,当汉语人群使用软件时,呈现左下界面,而英语人群使用软件时,呈现右下界面。Android项目开发。

    Android 百分比布局

    百分比布局&lt;android.support.percent.PercentLinearLayout android:id="@+id/tv_solid_number_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft=...

    Android布局文件大全

    Android布局文件的属性值解析说明: 1 android:id [为控件指定相应的ID] 2 android:text [指定控件当中显示的文字 需要注意的是 这里尽量使用strings xml文件当中的字符串] 3 android:gravity [指定View组件的对齐...

    Android布局管理器

    安卓布局讲解。各个控件的讲解,及其属性。代码展示。 1 2 &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" 4 android:layout_width="fill_parent" 5...

    android自定义百分比布局

    【android】通过父容器大小,子控件百分比布局 导入项目添加依赖,可以直接复制源码进项目; 1、在自己布局文件中,最外层容器添加引用 xmlns:badboy="http://schemas.android.com/apk/res-auto" badboy自己随意...

    com.google.android:flexbox:0.3.0-alpha2依赖资源

    要在主工程的gradle中添加版本信息或者自己在资源包中添加版本号,依赖此资源就可以实现FlexboxLayout与Recycleview的后续操作,我的主工程版本代码: ext { minSdkVersion = 9 targetSdkVersion = 25 ...

    ANDROID实验报告组件布局.pdf

    Android 开发 (实验五) 实验题目:Android 组件布局试验 指导老师: 班 级:计算机科学与技术系班 姓 名: 一、实验目的 1、掌握 Android 组件布局的使用方法 2、学会组件布局的重要属性与应用 3、能够根据需求,...

    android基础

    android布局和控件 LinearLayout:线性布局,从左到右 第一种方法实现界面布局:手动写布局 第二种方法实现界面布局:布局文件(layout中的activty_main.xml) 其实就是标签的嵌套,注意单标签、双标签 拨打电话的...

    Android 布局中的android:onClick的使用方法总结

    Android布局中的 android:onClick=“…”属性设置点击时从上下文中调用指定的方法。该属性值和要调用的方法名称完全一致。一般在Activity定义符合如下参数和返回值的函数并将方法名字符串指定为该属性值即可: ...

    Android 相对布局实例

    Android 相对布局实例 ,RalateLayout

    Android中使用RelativeLayout完成梅花布局的代码清单.pdf

    Android中使用RelativeLayout完成梅花布局的代码清单.pdf 学习资料 复习资料 教学资源

    Android 五大布局方式详解

    Android中常用的5大布局方式有以下几种: 线性布局(LinearLayout):按照垂直或者水平方向布局的组件。 帧布局(FrameLayout):组件从屏幕左上方布局组件。 表格布局(TableLayout):按照行列方式布局组件。 ...

    Android xml布局文件生成工具

    Android xml布局文件工具

    Android控件大全以及各布局空间的使用方式

    android:layout_width="fill_parent" android:layout_height="fill_parent"&gt; &lt;!-- FrameLayout - 层叠式布局。以左上角为起点,将 FrameLayout 内的元素一层覆盖一层地显示 --&gt; &lt;FrameLayout android...

    Android 五种Layout 布局

    介绍Android五中布局的一个示例代码.

    android实验2界面设计:基本组件.doc

    -- 在主布局添加文本框和密码框 --&gt; &lt;TextView android:text = "@string/password" android:layout_width="match_parent" android:layout_height="wrap_content"/&gt; &lt;EditText android:id="@+id/password" android:...

    android实验界面设计:布局管理器.doc

    android实验界面设计:布局管理器.doc

    Get清风android实验2界面设计:基本组件.doc

    -- 在主布局添加文本框和密码框 --&gt; &lt;TextView android:text = "@string/password" android:layout_width="match_parent" android:layout_height="wrap_content"/&gt; &lt;EditText android:id="@+id/password" android:...

    Android布局实现圆角边框效果

    首先,在res下面新建一个文件夹drawable,在drawable下面新建三个xml文件:shape_corner_down.xml、shape_corner_up.xml和shape_corner.xml,分别是下面两个角是圆角边框,上面两个角是圆角...solid android:color=#0

    Android流式布局简单实现

    Android流式布局简单实现,通过继承ViewGroup,重写OnLayout方法,实现标签的流式布局

Global site tag (gtag.js) - Google Analytics