`
lobin
  • 浏览: 427110 次
  • 性别: 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 五种Layout 布局

    本文将深入探讨Android的五种主要布局:LinearLayout、RelativeLayout、FrameLayout、GridLayout以及ConstraintLayout,并通过示例代码进行解析。 1. **LinearLayout**:线性布局是最基础的布局类型,它按照垂直或...

    Android 相对布局实例

    在Android开发中,布局管理器是构建用户界面的关键部分,其中相对布局(RelativeLayout)是一种常见的布局方式。相对布局允许我们根据各个视图之间的相对位置来安排它们,这为设计复杂且灵活的用户界面提供了可能。...

    Android布局属性总结

    本文将详细总结Android布局文件`layout.xml`中的各种属性及其用法。 首先,我们关注那些接受`true`或`false`作为值的属性: 1. `android:layout_centerHorizontal`:使视图在父布局的水平方向居中。 2. `android:...

    AndroidXML布局属性详解

    Android XML 布局属性详解 Android XML 布局属性是 Android 应用程序中最基本也是最重要的一部分。它负责控制屏幕上的各种控件的布局和排列。 Android XML 布局属性可以分为三类:第一类是属性值为 true 或 false ...

    Android页面布局总结

    ### Android页面布局详解 在Android开发中,布局是构建用户界面的基础。良好的布局不仅能够提升应用的美观度,还能提高用户体验。本文将详细介绍Android中三种常见的布局方式:LinearLayout(线性布局)、...

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

    在Android应用开发中,界面布局的设计是至关重要的。RelativeLayout是一种常用的布局管理器,它允许控件根据相对位置进行排列,提供了灵活的布局方案。本文主要介绍如何使用RelativeLayout来实现一个特殊的“梅花...

    android排版布局属性

    在Android应用开发中,布局是构建用户界面的关键环节,它决定了控件的排列方式和外观。其中,相对布局(RelativeLayout)是一种常用的布局方式,通过定义控件之间的相对位置,可以灵活地调整界面元素的布局。以下是...

    认识Android布局文件

    【Android布局文件详解】 在Android应用开发中,界面设计是一个至关重要的环节,而XML格式的布局文件正是构建这些界面的核心工具。布局文件定义了应用程序界面的结构,包括它所包含的控件、控件间的相对位置以及...

    Android学习笔记13:表格布局管理器TableLayout

    总结,TableLayout是Android开发中构建表格样布局的重要工具,通过灵活运用其属性和子视图配置,可以实现多种复杂的布局效果。结合实际项目中的TableLayoutDemo,开发者可以更好地理解和掌握这种布局管理器的使用。

    Android综合布局实例

    在Android应用开发中,布局(Layout)是构建用户界面的核心元素。`RelativeLayout`是一种常见的布局类型,它允许子视图(Views)相对彼此或者相对于父布局进行定位,从而实现复杂和灵活的界面设计。本实例将详细介绍...

    android布局属性总结文档

    在Android开发中,布局属性是构建用户界面的关键组成部分。这些属性允许开发者精确地控制各个UI组件的外观和位置。以下是对几种主要布局及其关键属性的详细说明: **LinearLayout**: 这是最基础的布局,可以将子...

    android框架布局的使用

    在Android开发中,框架布局(FrameLayout)是基础布局之一,它允许你在屏幕上放置一个或多个视图,并且这些视图会按照它们被添加到布局中的顺序覆盖彼此。本教程将深入探讨如何有效地使用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开发中,为UI元素添加虚线、圆角和渐变效果是常见的需求,可以提升应用的视觉吸引力。下面将详细讲解如何实现这些效果。 ### 一、虚线(Dashed Line) 在Android中,我们可以使用`Shape Drawable`来创建...

    Android 线性布局 实例

    在Android开发中,线性布局(LinearLayout)是基础且常用的布局管理器之一,它允许开发者按照垂直或水平方向排列子视图(View)。本实例针对初学者,将深入讲解线性布局的使用方法和特点。 一、线性布局介绍 线性...

    Android布局文件大全

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

    android 五大布局介绍附源码范例

    本篇文章将深入探讨Android的五大布局:LinearLayout(线性布局)、FrameLayout(单帧布局)、RelativeLayout(相对布局)、AbsoluteLayout(绝对布局)以及TableLayout(表格布局),并提供源码范例来帮助理解。...

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

    在Android应用开发中,界面设计是至关重要的,而布局管理器是实现高效界面设计的关键工具。本实验旨在帮助学生深入理解和熟练运用四种主要的布局管理器:LinearLayout、RelativeLayout、FrameLayout以及GridLayout,...

    Android六大布局详解

    Android系统提供了多种布局类型来满足不同场景下的需求,下面将详细介绍六种基本布局:线性布局(LinearLayout)、表格布局(TableLayout)、相对布局(RelativeLayout)、层布局(FrameLayout)、绝对布局...

    android布局

    ### Android布局详解 Android应用程序开发过程中,布局设计是至关重要的环节之一。良好的布局不仅能够提升应用的用户体验,还能让开发者更高效地管理界面元素。本文将深入探讨Android布局中的关键属性及其应用场景...

Global site tag (gtag.js) - Google Analytics