精华内容
参与话题
问答
  • Layout(布局)

    千次阅读 2018-10-12 22:41:14
    布局容器有5个区域:北、南、东、西和中间。中间区域面板是必须的,边缘的面板都是可选的。...布局可以进行嵌套,用户可以通过组合布局构建复杂的布局结构   <%@ page language="...utf-...

                    布局容器有5个区域:北、南、东、西和中间。中间区域面板是必须的,边缘的面板都是可选的。每个边缘区域面板都可以通过拖拽其边框改变大小,也可以点击折叠按钮将面板折叠起来。布局可以进行嵌套,用户可以通过组合布局构建复杂的布局结构

     

    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <title>Layout:通过标签创建布局</title>
        <!-- 引入easyUI:JQuery文件支持 -->
      	<script type="text/javascript" src="js/jquery-easyui-1.3.4/jquery.min.js"></script>
      	<!-- 引入easyUI -->
      	<script type="text/javascript" src="js/jquery-easyui-1.3.4/jquery.easyui.min.js"></script>
      	<!-- 引入中文支持 -->
      	<script type="text/javascript" src="js/jquery-easyui-1.3.4/locale/easyui-lang-zh_CN.js"></script>
      	<!-- 引入easyUI主题css文件 -->
      	<link rel="stylesheet" href="js/jquery-easyui-1.3.4/themes/default/easyui.css" type="text/css"></link>
      	<!-- 引入easyUI 图标导航文件 -->
      	<link rel="stylesheet" href="js/jquery-easyui-1.3.4/themes/icon.css" type="text/css"></link></head>
      
      <body>
      	<%
    		/*
    			为div标签增加名为'easyui-layout'的类ID
    			region:布局面板位置;  title:布局面板标题;  split:true时可以通过分割栏改变面板大小
    			iconCls:包含图标的CSS类ID(icon-**)
    			可以在标签中间层输入html或文本
    		*/  	
      	 %>
    	<div id="cc" class="easyui-layout" style="width:600px;height:400px;">   
    		<div data-options="region:'north',title:'上',split:false" style="height:100px;">Up</div>   
    	    <div data-options="region:'south',title:'下',split:true" style="height:100px;">Down</div>   
    	    <div data-options="region:'east',iconCls:'icon-no',title:'东',split:true" style="width:100px;"></div>   
    	    <div data-options="region:'west',title:'西',split:true" style="width:100px;"></div>   
    	    <div data-options="region:'center',title:'中'" style="padding:5px;background:#eee;"><h1>墨渐生微</h1></div>   
    	</div>
      </body>
    </html>
    

     

    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <title>Layout:使用完整页面创建布局</title>
        <!-- 引入easyUI:JQuery文件支持 -->
      	<script type="text/javascript" src="js/jquery-easyui-1.3.4/jquery.min.js"></script>
      	<!-- 引入easyUI -->
      	<script type="text/javascript" src="js/jquery-easyui-1.3.4/jquery.easyui.min.js"></script>
      	<!-- 引入中文支持 -->
      	<script type="text/javascript" src="js/jquery-easyui-1.3.4/locale/easyui-lang-zh_CN.js"></script>
      	<!-- 引入easyUI主题css文件 -->
      	<link rel="stylesheet" href="js/jquery-easyui-1.3.4/themes/default/easyui.css" type="text/css"></link>
      	<!-- 引入easyUI 图标导航文件 -->
      	<link rel="stylesheet" href="js/jquery-easyui-1.3.4/themes/icon.css" type="text/css"></link></head>
      
    	<body class="easyui-layout">
    		 <%
    			/*
    				为div标签增加名为'easyui-layout'的类ID
    				region:布局面板位置;  title:布局面板标题;  split:true时可以通过分割栏改变面板大小
    				iconCls:包含图标的CSS类ID(icon-**)
    			*/  	
    	  	 %>	  
    	    <div data-options="region:'north',title:'North Title',split:true" style="height:100px;"></div>   
    	    <div data-options="region:'south',title:'South Title',split:true" style="height:100px;"></div>   
    	    <div data-options="region:'east',iconCls:'icon-reload',title:'East',split:true" style="width:100px;"></div>   
    	    <div data-options="region:'west',title:'West',split:true" style="width:100px;"></div>   
    	    <div data-options="region:'center',title:'center title'" style="padding:5px;background:#eee;"></div>   
    	</body> 
    </html>
    

     

    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    	<head>
    	    <title>Layout:嵌套布局</title>
    	    <!-- 引入easyUI:JQuery文件支持 -->
    	  	<script type="text/javascript" src="js/jquery-easyui-1.3.4/jquery.min.js"></script>
    	  	<!-- 引入easyUI -->
    	  	<script type="text/javascript" src="js/jquery-easyui-1.3.4/jquery.easyui.min.js"></script>
    	  	<!-- 引入中文支持 -->
    	  	<script type="text/javascript" src="js/jquery-easyui-1.3.4/locale/easyui-lang-zh_CN.js"></script>
    	  	<!-- 引入easyUI主题css文件 -->
    	  	<link rel="stylesheet" href="js/jquery-easyui-1.3.4/themes/default/easyui.css" type="text/css"></link>
    	  	<!-- 引入easyUI 图标导航文件 -->
    	  	<link rel="stylesheet" href="js/jquery-easyui-1.3.4/themes/icon.css" type="text/css"></link>
    	</head>
      
    	<body class="easyui-layout">
    		<%
    			/*
    				fit:布局组件将自适应父容器
    				collapsed:是否显示折叠按钮
    			*/  	
    	  	 %>   
    	    <div data-options="region:'north'" style="height:100px"></div>   
    	    <div data-options="region:'center'">   
    	        <div class="easyui-layout" data-options="fit:true">   
    	            <div data-options="region:'west',collapsed:true" style="width:180px"></div>   
    	            <div data-options="region:'center'"></div>   
    	        </div>   
    	    </div>   
    	</body> 
    </html>
    

     

    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    	<head>
    	    <title>JS代码创建布局</title>
    	    <!-- 引入easyUI:JQuery文件支持 -->
    	  	<script type="text/javascript" src="js/jquery-easyui-1.3.4/jquery.min.js"></script>
    	  	<!-- 引入easyUI -->
    	  	<script type="text/javascript" src="js/jquery-easyui-1.3.4/jquery.easyui.min.js"></script>
    	  	<!-- 引入中文支持 -->
    	  	<script type="text/javascript" src="js/jquery-easyui-1.3.4/locale/easyui-lang-zh_CN.js"></script>
    	  	<!-- 引入easyUI主题css文件 -->
    	  	<link rel="stylesheet" href="js/jquery-easyui-1.3.4/themes/default/easyui.css" type="text/css"></link>
    	  	<!-- 引入easyUI 图标导航文件 -->
    	  	<link rel="stylesheet" href="js/jquery-easyui-1.3.4/themes/icon.css" type="text/css"></link>
    	  	
    	  	<script type="text/javascript">
    	  		$(document).ready(function(){
    		  		$('#cc').layout('add',{    
    				    region: 'west',    
    				    width: 180,    
    				    title: '西',    
    				    split: true,    
    				    tools: [{    
    					        iconCls:'icon-add',    
    					        handler:function(){alert('add');}    
    					    },{    
    					        iconCls:'icon-remove',    
    					        handler:function(){alert('remove');}    
    					    }]
    				});
    	  		});  		
    	  	</script>
    	</head>
      
    	<body>
    		<div id="cc" class="easyui-layout" style="width:600px;height:400px;"> 
    			<div data-options="region:'center',title:'center title'" style="padding:5px;background:#eee;"></div> 
    		</div>
    	</body> 
    </html>
    

     

    展开全文
  • 关于Layout的总结。

    千次阅读 2018-07-14 06:54:23
    1.关于coordinatorLayoutCoordinatorLayout简介CoordinatorLayout是在 Google IO/15 大会发布的,遵循Material 风格,包含在 support Library中,结合AppbarLayout, CollapsingToolbarLayout等 可 产生各种炫酷的...

    CoordinatorLayout简介

    CoordinatorLayout是在 Google IO/15 大会发布的,遵循Material 风格,包含在 support Library中,结合AppbarLayout, CollapsingToolbarLayout等 可 产生各种炫酷的效果


    简单来说就是

    • 作为最上层的View
    • 作为一个 容器与一个或者多个子View进行交互
    与AppbarLayout组合的滚动布局(RecyclerView, NestedScrollView等),需要设置 app:layout_behavior = "@string/appbar_scrolling_view_behavior" .没有设置的话, AppbarLayout将不会响应滚动布局的滚动事件.

    类型说明
    int SCROLL_FLAG_ENTER_ALWAYSWhen entering (scrolling on screen) the view will scroll on any downwards scroll event, regardless of whether the scrolling view is also scrolling.
    int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSEDAn additional flag for 'enterAlways' which modifies the returning view to only initially scroll back to it's collapsed height.
    int SCROLL_FLAG_EXIT_UNTIL_COLLAPSEDWhen exiting (scrolling off screen) the view will be scrolled until it is 'collapsed'.
    int SCROLL_FLAG_SCROLLThe view will be scroll in direct relation to scroll events.
    int SCROLL_FLAG_SNAPUpon a scroll ending, if the view is only partially visible then it will be snapped and scrolled to it's closest edge.
    类型说明
    int SCROLL_FLAG_ENTER_ALWAYSW((entering) / (scrolling on screen))下拉的时候,这个View也会跟着滑出。
    int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED另一种enterAlways,但是只显示折叠后的高度。
    int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED((exiting) / (scrolling off screen))上拉的时候,这个View会跟着滑动直到折叠。
    int SCROLL_FLAG_SCROLL这个View将会响应Scroll事件
    int SCROLL_FLAG_SNAP在Scroll滑动事件结束以前 ,如果这个View部分可见,那么这个View会停在最接近当前View的位置

    我们可以通过两种 方法设置这个Flag

    • 方法一
     setScrollFlags(int) 
    
    • 方法二
     app:layout_scrollFlags="scroll|enterAlways"
    

    注意事项

    AppBarLayout必须作为CoordinatorLayout的直接子View,否则它的大部分功能将不会生效,如layout_scrollFlags等。


    CollapsingToolbarLayout

    CollapsingToolbarLayout继承与FrameLayout,官网地址,请自备梯子。

    简单来说 ,CollapsingToolbarLayout是工具栏的包装器,它通常作为AppBarLayout的孩子。主要实现以下功能

    • Collapsing title(可以折叠 的 标题 )
    • Content scrim(内容装饰),当我们滑动的位置 到达一定阀值的时候,内容 装饰将会被显示或者隐藏
    • Status bar scrim(状态栏布)
    • Parallax scrolling children,滑动的时候孩子呈现视觉特差效果
    • Pinned position children,固定位置的 孩子

    下面我们一起来看一下几个常量

    常量解释说明
    int COLLAPSE_MODE_OFFThe view will act as normal with no collapsing behavior.(这个 View将会 呈现正常的结果,不会表现出折叠效果)
    int COLLAPSE_MODE_PARALLAXThe view will scroll in a parallax fashion. See setParallaxMultiplier(float) to change the multiplier used.(在滑动的时候这个View 会呈现 出 视觉特差效果 )
    int COLLAPSE_MODE_PINThe view will pin in place until it reaches the bottom of the CollapsingToolbarLayout.(当这个View到达 CollapsingToolbarLayout的底部的时候,这个View 将会被放置,即代替整个CollapsingToolbarLayout)

    我们有两种方法可以设置这个常量,

    方法一:在代码中使用这个方法

    setCollapseMode(int collapseMode)
    

    方法 二:在布局文件中使用自定义属性

    app:layout_collapseMode="pin"
    

    DrawerLayout 简单使用

    介绍

    drawerLayout是Support Library包中实现了侧滑菜单效果的控件,可以说drawerLayout是因为第三方控件如MenuDrawer等的出现之后,google借鉴而出现的产物。drawerLayout分为侧边菜单和主内容区两部分,侧边菜单可以根据手势展开与隐藏(drawerLayout自身特性),主内容区的内容可以随着菜单的点击而变化(这需要使用者自己实现)。

    实用

    DrawerLayout 实用比较简单,这里只介绍简单使用和常用API。

    1. 在布局文件中使用DrawerLayout 进行设置。如下示例代码:
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/dlyt_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
    
        <!-- 内容 -->
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <Button
                android:id="@+id/btn_context"
                android:text="context"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
    
        </FrameLayout>
    
        <!-- 左边菜单 -->
        <FrameLayout
            android:background="@color/colorAccent"
            android:layout_gravity="start"
            android:layout_width="200dp"
            android:layout_height="match_parent">
            <Button
                android:id="@+id/btn_left_menu"
                android:text="left menu"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        </FrameLayout>
    
        <!-- 右边菜单 -->
        <FrameLayout
            android:background="@color/colorAccent"
            android:layout_gravity="end"
            android:layout_width="200dp"
            android:layout_height="match_parent">
            <Button
                android:id="@+id/btn_right_menu"
                android:text="right menu"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        </FrameLayout>
    </android.support.v4.widget.DrawerLayout>
    
    

    在 DrawerLayout 布局中有三个元素,

    1. view 主体
    2. 左边菜单:
      左边菜单的设定使用android:layout_gravity="start" 设置。
    3. 右边菜单:
      右边菜单的设定使用android:layout_gravity="end" 设置。

    通过上面,我们就已经实现了左右划出菜单效果。
    如果我们需要加上一些控制逻辑,可能就需要一些的一些API了。

    DrawerLayout 中部分 API 介绍

    1. isDrawerOpen(@EdgeGravity int drawerGravity) : 判断菜单是否打开。

    传入参数:

    • GravityCompat.START : 左边菜单是否打开。
    • GravityCompat.END : 右边菜单是否打开。

    返回值

    • 打开 : true
    • 关闭 : false
    1. openDrawer(@EdgeGravity int gravity) : 打开菜单

    传入参数:

    • GravityCompat.START : 打开左边菜单。
    • GravityCompat.END : 打开右边菜单。
    1. closeDrawer(@EdgeGravity int gravity) : 关闭菜单

    传入参数:

    • GravityCompat.START : 关闭左边菜单。
    • GravityCompat.END : 关闭右边菜单。
    1. addDrawerListener(@NonNull DrawerListener listener) : 添加监听
    2. DrawerListener 类
    • onDrawerSlide(View drawerView, float slideOffset) : 滑动时调用
    • onDrawerOpened(View drawerView) : 打开菜单时调用
    • onDrawerClosed(View drawerView) : 关闭菜单时调用
    • onDrawerStateChanged(@State int newState) : 菜单状态改变时调用

    其他API查看源码就会明白如何使用。

    如下Java示例代码:

    //添加监听
    DrawerLayout.addDrawerListener(new DrawerViewListener());
    
    private class DrawerViewListener implements DrawerLayout.DrawerListener {
        @Override
        public void onDrawerSlide(View drawerView, float slideOffset) {
        //滑动时调用
        }
    
        @Override
        public void onDrawerOpened(View drawerView) {
        //打开菜单时调用
        }
    
        @Override
        public void onDrawerClosed(View drawerView) {
        //关闭菜单时调用
        }
    
        @Override
        public void onDrawerStateChanged(int newState) {
        //菜单状态改变时调用
        }
    }
    

    AutoCompleteTextView

    AutoCompleteTextView常用属性

    属性描述
    android:completionHint设置出现在下拉菜单底部的提示信息
    android:completionThreshold设置触发补全提示信息的字符个数
    android:dropDownHorizontalOffset设置下拉菜单于文本框之间的水平偏移量
    android:dropDownHeight设置下拉菜单的高度
    android:dropDownWidth设置下拉菜单的宽度
    android:singleLine设置单行显示文本内容
    android:dropDownVerticalOffset设置下拉菜单于文本框之间的垂直偏移量

    使用ArrayAdapter来作为AutoCompleteTextView的数据适配器

    • 简单的xml布局
    <AutoCompleteTextView
        android:id="@+id/tv_search"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/hint_type"
        android:completionHint="@string/chint_recent"
        android:completionThreshold="1" />
    
    • 默认AutoCompleteTextView中的数据保存在SharedPreferences中,故将SharedPreferences做了简单的API封装以方便数据存取,详细的SharedPreferences请参考这里:SharedPreferences
    // 从SharedPreferences中获取历史记录数据
    private String getHistoryFromSharedPreferences(String key) {
        SharedPreferences sp = getSharedPreferences(SP_NAME, MODE_PRIVATE);
        return sp.getString(key, SP_EMPTY_TAG);
    }
    
    // 将历史记录数据保存到SharedPreferences中
    private void saveHistoryToSharedPreferences(String key, String history) {
        SharedPreferences sp = getSharedPreferences(SP_NAME, MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.putString(key, history);
        editor.apply();
    }
    
    // 清除保存在SharedPreferences中的历史记录数据
    private void clearHistoryInSharedPreferences() {
        SharedPreferences sp = getSharedPreferences(SP_NAME, MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.clear();
        editor.apply();
    }
    
    • 使用默认适配器的AutoCompleteTextView相关初始化
    private void initSearchView() {
        mSearchTv = (AutoCompleteTextView) findViewById(R.id.tv_search);
        String[] mSearchHistoryArray = getHistoryArray(SP_KEY_SEARCH);
        mSearchAdapter = new ArrayAdapter<>(
                this,
                android.R.layout.simple_dropdown_item_1line,
                mSearchHistoryArray
        );
        mSearchTv.setAdapter(mSearchAdapter);  // 设置适配器
    
        // 设置下拉提示框的高度为200dp
        // mAutoCompleteTv.setDropDownHeight();      // 或XML中为android:dropDownHeight="200dp"
    
        // 默认当输入2个字符以上才会提示, 现在当设置输入1个字符就自动提示
        // mAutoCompleteTv.setThreshold(1);          // 或XML中为android:completionThreshold="1"
    
        // 设置下拉提示框中底部的提示
        // mAutoCompleteTv.setCompletionHint("最近的5条记录");
    
        // 设置单行输入限制
        // mAutoCompleteTv.setSingleLine(true);
    }
    
    private String[] getHistoryArray(String key) {
        String[] array = getHistoryFromSharedPreferences(key).split(SP_SEPARATOR);
        if (array.length > MAX_HISTORY_COUNT) {         // 最多只提示最近的50条历史记录
            String[] newArray = new String[MAX_HISTORY_COUNT];
            System.arraycopy(array, 0, newArray, 0, MAX_HISTORY_COUNT); // 实现数组间的内容复制
        }
        return array;
    }
    
    • 保存AutoCompleteTextView中的历史记录数据到SharedPreferences中
    private void saveSearchHistory() {
        String text = mSearchTv.getText().toString().trim();       // 获取搜索框文本信息
        if (TextUtils.isEmpty(text)) {                      // null or ""
            Toast.makeText(this, "Please type something again.", Toast.LENGTH_SHORT).show();
            return;
        }
    
        String old_text = getHistoryFromSharedPreferences(SP_KEY_SEARCH);// 获取SP中保存的历史记录
        StringBuilder sb;
        if (SP_EMPTY_TAG.equals(old_text)) {
            sb = new StringBuilder();
        } else {
            sb = new StringBuilder(old_text);
        }
        sb.append(text + SP_SEPARATOR);      // 使用逗号来分隔每条历史记录
    
        // 判断搜索内容是否已存在于历史文件中,已存在则不再添加
        if (!old_text.contains(text + SP_SEPARATOR)) {
            saveHistoryToSharedPreferences(SP_KEY_SEARCH, sb.toString());  // 实时保存历史记录
            mSearchAdapter.add(text);        // 实时更新下拉提示框中的历史记录
            Toast.makeText(this, "Search saved: " + text, Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "Search existed: " + text, Toast.LENGTH_SHORT).show();
        }
    }
    

    上面代码中,为了能够实时更新下拉提示框中的历史记录,需要在保存数据后再调用ArrayAdapter.add()方法,而不是调用ArrayAdapter.notifyDataSetChanged()

    • 实时清除下拉提示框中的历史记录
    clearHistoryInSharedPreferences();          // 试试清除历史记录
    mSearchAdapter.clear();                     // 实时清除下拉提示框中的历史记录
    
    • 效果演示
    arrayadapter_autocomplete_textview_320x512.gif

    使用自定义AutoCompleteAdapter来作为AutoCompleteTextView的数据适配器

    • 简单的xml布局

    使用RelativeLayout来容纳AutoCompleteTextView和ImageView,其中ImageView位于右侧,用于点击清除AutoCompleteTextView的内容

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:gravity="center_vertical">
    
        <AutoCompleteTextView
            android:id="@+id/tv_custom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingStart="12dp"
            android:paddingEnd="40dp"
            android:hint="@string/hint_type"/>
    
        <ImageView
            android:id="@+id/iv_custom"
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:layout_marginEnd="10dp"
            android:layout_alignParentEnd="true"
            android:layout_centerVertical="true"
            android:scaleType="fitCenter"
            android:src="@drawable/ic_action_name"
            android:contentDescription="@null"/>
    </RelativeLayout>
    
    • 使用自定义适配器的AutoCompleteTextView相关初始化
    private void initCustomView() {
        mCustomTv = (AutoCompleteTextView) findViewById(R.id.tv_custom);
        mDeleteIv = (ImageView) findViewById(R.id.iv_custom);
        mDeleteIv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mCustomTv.setText("");              // 清空TextView的内容
            }
        });
    
        ArrayList<String> mOriginalValues = new ArrayList<>();
        String[] mCustomHistoryArray = getHistoryArray(SP_KEY_CUSTOM);
        mOriginalValues.addAll(Arrays.asList(mCustomHistoryArray));     // String[] => ArrayList<String>
        
        mCustomAdapter = new AutoCompleteAdapter(this, mOriginalValues);
        mCustomAdapter.setDefaultMode(AutoCompleteAdapter.MODE_STARTSWITH | AutoCompleteAdapter.MODE_SPLIT);// 设置匹配模式
        mCustomAdapter.setSupportPreview(true);     // 支持使用特殊符号进行预览提示内容,默认为'@'
    
        simpleItemHeight = mCustomAdapter.getSimpleItemHeight();
        Toast.makeText(this, "simpleItemHeight: " + simpleItemHeight, Toast.LENGTH_SHORT).show(); // 103
    
        mCustomAdapter.setOnFilterResultsListener(new AutoCompleteAdapter.OnFilterResultsListener() {
            @Override
            public void onFilterResultsListener(int count) {
                curCount = count;
                if (count > MAX_ONCE_MATCHED_ITEM) {        // 限制提示框最多要显示的记录行数
                    curCount = MAX_ONCE_MATCHED_ITEM;
                }
                if (curCount != prevCount) {                // 仅当目前的数目和之前的不同才重新设置下拉框高度,避免重复设置
                    prevCount = curCount;
                    mCustomTv.setDropDownHeight(simpleItemHeight * curCount);
                }
            }
        });
    
        mCustomAdapter.setOnSimpleItemDeletedListener(new AutoCompleteAdapter.OnSimpleItemDeletedListener() {
            @Override
            public void onSimpleItemDeletedListener(String value) {
                String old_history = getHistoryFromSharedPreferences(SP_KEY_CUSTOM);    // 获取之前的记录
                String new_history = old_history.replace(value + SP_SEPARATOR, "");    // 用空字符串替换掉要删除的记录
                saveHistoryToSharedPreferences(SP_KEY_CUSTOM, new_history);             // 保存修改过的记录
            }
        });
    
        mCustomTv.setAdapter(mCustomAdapter);       //
        mCustomTv.setThreshold(1);                  //
    
        // 设置下拉时显示的提示行数 (此处不设置也可以,因为在AutoCompleteAdapter中有专门的事件监听来实时设置提示框的高度)
        // mCustomTv.setDropDownHeight(simpleItemHeight * MAX_ONCE_MATCHED_ITEM);
    }
    
    • 保存AutoCompleteTextView中的历史记录数据到SharedPreferences中
    private void saveCustomHistory() {
        String text = mCustomTv.getText().toString().trim();     // 获取搜索框信息
        if (TextUtils.isEmpty(text)) {          // null or ""
            Toast.makeText(this, "Please type something again.", Toast.LENGTH_SHORT).show();
            return;
        }
    
        String old_text = getHistoryFromSharedPreferences(SP_KEY_CUSTOM);    // 获取SP中保存的历史记录
        StringBuilder sb;
        if (SP_EMPTY_TAG.equals(old_text)) {
            sb = new StringBuilder();
        } else {
            sb = new StringBuilder(old_text);
        }
        sb.append(text + SP_SEPARATOR);      // 使用逗号来分隔每条历史记录
    
        // 判断搜索内容是否已存在于历史文件中,已存在则不再添加
        if (!old_text.contains(text + SP_SEPARATOR)) {
            saveHistoryToSharedPreferences(SP_KEY_CUSTOM, sb.toString());  // 实时保存历史记录
            mCustomAdapter.add(text);        // 实时更新下拉提示框中的历史记录
            Toast.makeText(this, "Custom saved: " + text, Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "Custom existed: " + text, Toast.LENGTH_SHORT).show();
        }
    }
    
    • 实时清除下拉提示框中的历史记录
    clearHistoryInSharedPreferences();      // 试试清除历史记录
    mCustomAdapter.clear();                 // 实时清除下拉提示框中的历史记录
    
    • 自定义适配器AutoCompleteAdapter

    AutoCompleteAdapter参考了ArrayAdapter的部分源代码,继承自BaseAdapter并实现Filterable接口,实现了以下功能:

    1. 实现自动补全的匹配模式的配置,有三种可选匹配模式:
    MODE_CONTAINS / MODE_STARTSWITH(default) / MODE_SPLIT
    
    1. 实现匹配成功事件的回调,用于根据匹配结果数来动态设置下拉提示框的高度
    2. 实现删除匹配结果中子项的事件回调,用于实时更新存储在SharedPreferences的历史记录数据
    3. 支持使用@字符来预览所有提示内容
    public class AutoCompleteAdapter extends BaseAdapter implements Filterable {
    
        private static final int MODE_NONE = 0x000;                 // 0000b
        public static final int MODE_CONTAINS = 0x001;              // 0001b
        public static final int MODE_STARTSWITH = 0x002;            // 0010b
        public static final int MODE_SPLIT = 0x004;                 // 0100b
        private static final String SPLIT_SEPARATOR = "[,.\\s]+";  // 分隔符,默认为空白符、英文逗号、英文句号
        private static boolean isFound = false;   // 当MODE_STARTSWITH模式匹配成功时,不再进行MODE_SPLIT模式的匹配
        private int defaultMode = MODE_STARTSWITH;                  // 0110b
    
        private LayoutInflater inflater;
        private ArrayFilter mArrayFilter;
        private ArrayList<String> mOriginalValues;      // 所有的item
        private List<String> mObjects;                  // 过滤后的item
        private final Object mLock = new Object();      // 同步锁
        private int maxMatch = 10;                      // 最多显示的item数目,负数表示全部
        private int simpleItemHeight;                   // 单行item的高度值,故需要在XML中固定父布局的高度值
    
        private char previewChar = '@';                 // 默认字符
        private boolean isSupportPreview = false;       // 是否可以使用@符号进行预览全部提示内容
    
        public AutoCompleteAdapter(Context context, ArrayList<String> mOriginalValues) {
            this(context, mOriginalValues, -1);
        }
    
        public AutoCompleteAdapter(Context context, ArrayList<String> mOriginalValues, int maxMatch) {
            this.mOriginalValues = mOriginalValues;
            // 初始化时将其设置成mOriginalValues,避免在未进行数据保存时执行删除操作导致程序的崩溃
            this.mObjects = mOriginalValues;   
            this.maxMatch = maxMatch;
            inflater = LayoutInflater.from(context);
            initViewHeight();
        }
    
        private void initViewHeight() {
            View view = inflater.inflate(R.layout.simple_dropdown_item_1line, null);
            LinearLayout linearLayout = (LinearLayout) view.findViewById(R.id.layout_item);
            linearLayout.measure(0, 0);
            // 其他方法获取的高度值会因View尚未被绘制而获取到0
            simpleItemHeight = linearLayout.getMeasuredHeight();
        }
    
        public int getSimpleItemHeight() {
            return simpleItemHeight;                // 5 * 2 + 28(dp) => 103(px)
        }
        
        public void setSupportPreview(boolean isSupportPreview){
            this.isSupportPreview = isSupportPreview;
        }
    
        public void setSupportPreview(boolean isSupportPreview, char previewChar){
            this.isSupportPreview = isSupportPreview;
            this.previewChar = previewChar;
        }
    
        @Override
        public int getCount() {
            return mObjects.size();
        }
    
        @Override
        public Object getItem(int position) {
            return mObjects.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if (convertView == null) {
                holder = new ViewHolder();
                convertView = inflater.inflate(R.layout.simple_dropdown_item_1line, null);
                holder.tv = (TextView) convertView.findViewById(R.id.tv_simple_item);
                holder.iv = (ImageView) convertView.findViewById(R.id.iv_simple_item);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            holder.tv.setText(mObjects.get(position));
            holder.iv.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String value = mObjects.remove(position);
    
                    if (mDeleteListener != null) {
                        mDeleteListener.onSimpleItemDeletedListener(value);
                    }
    
                    if (mFilterListener != null) {
                        mFilterListener.onFilterResultsListener(mObjects.size());
                    }
    
                    mOriginalValues.remove(value);
                    notifyDataSetChanged();
                }
            });
    
            return convertView;
        }
    
        private static class ViewHolder {
            TextView tv;
            ImageView iv;
        }
    
        public void setDefaultMode(int defaultMode) {
            this.defaultMode = defaultMode;
        }
    
        public void add(String item) {
            mOriginalValues.add(item);
            notifyDataSetChanged();         //
        }
    
        public void clear() {
            if(mOriginalValues != null && !mOriginalValues.isEmpty()) {
                mOriginalValues.clear();
                notifyDataSetChanged();         //
            }
        }
    
        // Interface
        public interface OnSimpleItemDeletedListener {
            void onSimpleItemDeletedListener(String value);
        }
    
        private OnSimpleItemDeletedListener mDeleteListener;
    
        public void setOnSimpleItemDeletedListener(OnSimpleItemDeletedListener listener) {
            this.mDeleteListener = listener;
        }
    
        // Interface
        public interface OnFilterResultsListener {
            void onFilterResultsListener(int count);
        }
    
        private OnFilterResultsListener mFilterListener;
    
        public void setOnFilterResultsListener(OnFilterResultsListener listener) {
            this.mFilterListener = listener;
        }
    
        @Override
        public Filter getFilter() {
            if (mArrayFilter == null) {
                mArrayFilter = new ArrayFilter(mFilterListener);
            }
            return mArrayFilter;
        }
    
        private class ArrayFilter extends Filter {
    
            private OnFilterResultsListener listener;
    
            public ArrayFilter(OnFilterResultsListener listener) {
                this.listener = listener;
            }
    
            @Override
            protected FilterResults performFiltering(CharSequence prefix) {
                FilterResults results = new FilterResults();
    
                if (mOriginalValues == null) {
                    synchronized (mLock) {
                        mOriginalValues = new ArrayList<>(mObjects);
                    }
                }
    
                if (prefix == null || prefix.length() == 0) {
                    synchronized (mLock) {
                        ArrayList<String> list = new ArrayList<>(mOriginalValues);
                        results.values = list;
                        results.count = list.size();
                    }
                } else {
                    if (isSupportPreview) {
                        int index = prefix.toString().indexOf(String.valueOf(previewChar));
                        if (index != -1) {
                            prefix = prefix.toString().substring(index + 1);
                        }
                    }
                
                    String prefixString = prefix.toString().toLowerCase();      // prefixString
                    final int count = mOriginalValues.size();                   // count
                    final ArrayList<String> newValues = new ArrayList<>(count); // newValues
    
                    for (int i = 0; i < count; i++) {
                        final String value = mOriginalValues.get(i);            // value
                        final String valueText = value.toLowerCase();           // valueText
    
                        // 1. 匹配所有
                        if ((defaultMode & MODE_CONTAINS) != MODE_NONE) {
                            if (valueText.contains(prefixString)) {
                                newValues.add(value);
                            }
                        } else {    // support: defaultMode = MODE_STARTSWITH | MODE_SPLIT
                            // 2. 匹配开头
                            if ((defaultMode & MODE_STARTSWITH) != MODE_NONE) {
                                if (valueText.startsWith(prefixString)) {
                                    newValues.add(value);
                                    isFound = true;
                                }
                            }
                            // 3. 分隔符匹配,效率低
                            if (!isFound && (defaultMode & MODE_SPLIT) != MODE_NONE) {
                                final String[] words = valueText.split(SPLIT_SEPARATOR);
                                for (String word : words) {
                                    if (word.startsWith(prefixString)) {
                                        newValues.add(value);
                                        break;
                                    }
                                }
                            }
                            if(isFound) {   // 若在MODE_STARTSWITH模式中匹配,则再次复位进行下一次判断
                                isFound = false;
                            }
                        }
    
                        if (maxMatch > 0) {             // 限制显示item的数目
                            if (newValues.size() > maxMatch - 1) {
                                break;
                            }
                        }
                    } // for (int i = 0; i < count; i++)
                    results.values = newValues;
                    results.count = newValues.size();
                }
    
                return results;
            }
    
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                //noinspection unchecked
                mObjects = (List<String>) results.values;
    
                if (results.count > 0) {
                    // 由于当删除提示框中的记录行时,而AutoCompleteTextView此时内容又不改变,故不会触发FilterResults事件
                    // 导致删除记录行时,提示框的高度不会发生相应的改变
                    // 解决方法:需要在ImageView的点击监听器中也调用OnFilterResultsListener.onFilterResultsListener()
                    // 来共同完成
                    if (listener != null) {
                        listener.onFilterResultsListener(results.count);
                    }
                    notifyDataSetChanged();
                } else {
                    notifyDataSetInvalidated();
                }
            }
        }
    }
    
    • 下拉提示框的item布局simple_dropdown_item_1line.xml

    这里需要固定父类控件LinearLayout的高度,在AutoCompleteAdapter中会获取其高度用于设置AutoCompleteTextView的下拉菜单的高度

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/layout_item"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="28dp"
        android:padding="5dp"
        android:gravity="center_vertical">
    
        <TextView
            android:id="@+id/tv_simple_item"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:paddingStart="5dp"
            android:paddingEnd="0dp"
            android:text="@string/text_nothing"
            android:textAllCaps="false"
            android:textSize="18sp"
            android:textColor="#000"/>
    
        <ImageView
            android:id="@+id/iv_simple_item"
            android:layout_width="18dp"
            android:layout_height="18dp"
            android:layout_marginEnd="5dp"
            android:src="@drawable/ic_action_name"
            android:contentDescription="@null"
            android:scaleType="fitCenter" />
    </LinearLayout>
    
    • 效果演示
    • 支持使用@字符来预览所有提示内容


    展开全文
  • vue、Layout 布局、Layout 属性、vue Layout 全部布局、vue Layout 全部属性

    设计规则

    协助进行页面级整体布局。

    尺寸

    一级导航项偏左靠近 logo 放置,辅助菜单偏右放置。

    • 顶部导航(大部分系统):一级导航高度 64px,二级导航 48px
    • 顶部导航(展示类页面):一级导航高度 80px,二级导航 56px
    • 顶部导航高度的范围计算公式为:48+8n
    • 侧边导航宽度的范围计算公式:200+8n

    交互

    • 一级导航和末级的导航需要在可视化的层面被强调出来;
    • 当前项应该在呈现上优先级最高;
    • 当导航收起的时候,当前项的样式自动赋予给它的上一个层级;
    • 左侧导航栏的收放交互同时支持手风琴和全展开的样式,根据业务的要求进行适当的选择。

    视觉

    导航样式上需要根据信息层级合理的选择样式:

    • 大色块强调

    建议用于底色为深色系时,当前页面父级的导航项。

    • 高亮火柴棍

    当导航栏底色为浅色系时使用,可用于当前页面对应导航项,建议尽量在导航路径的最终项使用。

    • 字体高亮变色

    从可视化层面,字体高亮的视觉强化力度低于大色块,通常在当前项的上一级使用。

    • 字体放大

    12px14px 是导航的标准字号,14 号字体用在一、二级导航中。字号可以考虑导航项的等级做相应选择。

    组件概述

    Layout:布局容器,其下可嵌套 Header Sider Content FooterLayout 本身,可以放在任何父容器中。
    Header:顶部布局,自带默认样式,其下可嵌套任何元素,只能放在 Layout 中。
    Sider:侧边栏,自带默认样式及基本功能,其下可嵌套任何元素,只能放在 Layout 中。
    Content:内容部分,自带默认样式,其下可嵌套任何元素,只能放在 Layout中。
    Footer:底部布局,自带默认样式,其下可嵌套任何元素,只能放在 Layout中。

    代码演示

    1.基本结构

    在这里插入图片描述
    典型的页面布局。

    <template>
      <div id="components-layout-demo-basic">
        <a-layout>
          <a-layout-header>Header</a-layout-header>
          <a-layout-content>Content</a-layout-content>
          <a-layout-footer>Footer</a-layout-footer>
        </a-layout>
    
        <a-layout>
          <a-layout-header>Header</a-layout-header>
          <a-layout>
            <a-layout-sider>Sider</a-layout-sider>
            <a-layout-content>Content</a-layout-content>
          </a-layout>
          <a-layout-footer>Footer</a-layout-footer>
        </a-layout>
    
        <a-layout>
          <a-layout-header>Header</a-layout-header>
          <a-layout>
            <a-layout-content>Content</a-layout-content>
            <a-layout-sider>Sider</a-layout-sider>
          </a-layout>
          <a-layout-footer>Footer</a-layout-footer>
        </a-layout>
    
        <a-layout>
          <a-layout-sider>Sider</a-layout-sider>
          <a-layout>
            <a-layout-header>Header</a-layout-header>
            <a-layout-content>Content</a-layout-content>
            <a-layout-footer>Footer</a-layout-footer>
          </a-layout>
        </a-layout>
      </div>
    </template>
    <style>
    #components-layout-demo-basic {
      text-align: center;
    }
    #components-layout-demo-basic .ant-layout-header,
    #components-layout-demo-basic .ant-layout-footer {
      background: #7dbcea;
      color: #fff;
    }
    #components-layout-demo-basic .ant-layout-footer {
      line-height: 1.5;
    }
    #components-layout-demo-basic .ant-layout-sider {
      background: #3ba0e9;
      color: #fff;
      line-height: 120px;
    }
    #components-layout-demo-basic .ant-layout-content {
      background: rgba(16, 142, 233, 1);
      color: #fff;
      min-height: 120px;
      line-height: 120px;
    }
    #components-layout-demo-basic > .ant-layout {
      margin-bottom: 48px;
    }
    #components-layout-demo-basic > .ant-layout:last-child {
      margin: 0;
    }
    </style>
    

    2.自定义触发器

    在这里插入图片描述
    要使用自定义触发器,可以设置 :trigger="null" 来隐藏默认设定。

    <template>
      <a-layout id="components-layout-demo-custom-trigger">
        <a-layout-sider
          :trigger="null"
          collapsible
          v-model="collapsed"
        >
          <div class="logo" />
          <a-menu theme="dark" mode="inline" :defaultSelectedKeys="['1']">
            <a-menu-item key="1">
              <a-icon type="user" />
              <span>nav 1</span>
            </a-menu-item>
            <a-menu-item key="2">
              <a-icon type="video-camera" />
              <span>nav 2</span>
            </a-menu-item>
            <a-menu-item key="3">
              <a-icon type="upload" />
              <span>nav 3</span>
            </a-menu-item>
          </a-menu>
        </a-layout-sider>
        <a-layout>
          <a-layout-header style="background: #fff; padding: 0">
            <a-icon
              class="trigger"
              :type="collapsed ? 'menu-unfold' : 'menu-fold'"
              @click="()=> collapsed = !collapsed"
            />
          </a-layout-header>
          <a-layout-content :style="{ margin: '24px 16px', padding: '24px', background: '#fff', minHeight: '280px' }">
            Content
          </a-layout-content>
        </a-layout>
      </a-layout>
    </template>
    <script>
    export default {
      data(){
        return {
          collapsed: false,
        }
      },
    }
    </script>
    <style>
    #components-layout-demo-custom-trigger .trigger {
      font-size: 18px;
      line-height: 64px;
      padding: 0 24px;
      cursor: pointer;
      transition: color .3s;
    }
    
    #components-layout-demo-custom-trigger .trigger:hover {
      color: #1890ff;
    }
    
    #components-layout-demo-custom-trigger .logo {
      height: 32px;
      background: rgba(255,255,255,.2);
      margin: 16px;
    }
    </style>
    

    3.顶部-侧边布局-通栏

    在这里插入图片描述
    同样拥有顶部导航及侧边栏,区别是两边未留边距,多用于应用型的网站。

    <template>
      <a-layout id="components-layout-demo-top-side-2">
        <a-layout-header class="header">
          <div class="logo" />
          <a-menu
            theme="dark"
            mode="horizontal"
            :defaultSelectedKeys="['2']"
            :style="{ lineHeight: '64px' }"
          >
            <a-menu-item key="1">nav 1</a-menu-item>
            <a-menu-item key="2">nav 2</a-menu-item>
            <a-menu-item key="3">nav 3</a-menu-item>
          </a-menu>
        </a-layout-header>
        <a-layout>
          <a-layout-sider width="200" style="background: #fff">
            <a-menu
              mode="inline"
              :defaultSelectedKeys="['1']"
              :defaultOpenKeys="['sub1']"
              :style="{ height: '100%', borderRight: 0 }"
            >
              <a-sub-menu key="sub1">
                <span slot="title"><a-icon type="user" />subnav 1</span>
                <a-menu-item key="1">option1</a-menu-item>
                <a-menu-item key="2">option2</a-menu-item>
                <a-menu-item key="3">option3</a-menu-item>
                <a-menu-item key="4">option4</a-menu-item>
              </a-sub-menu>
              <a-sub-menu key="sub2">
                <span slot="title"><a-icon type="laptop" />subnav 2</span>
                <a-menu-item key="5">option5</a-menu-item>
                <a-menu-item key="6">option6</a-menu-item>
                <a-menu-item key="7">option7</a-menu-item>
                <a-menu-item key="8">option8</a-menu-item>
              </a-sub-menu>
              <a-sub-menu key="sub3">
                <span slot="title"><a-icon type="notification" />subnav 3</span>
                <a-menu-item key="9">option9</a-menu-item>
                <a-menu-item key="10">option10</a-menu-item>
                <a-menu-item key="11">option11</a-menu-item>
                <a-menu-item key="12">option12</a-menu-item>
              </a-sub-menu>
            </a-menu>
          </a-layout-sider>
          <a-layout style="padding: 0 24px 24px">
            <a-breadcrumb style="margin: 16px 0">
              <a-breadcrumb-item>Home</a-breadcrumb-item>
              <a-breadcrumb-item>List</a-breadcrumb-item>
              <a-breadcrumb-item>App</a-breadcrumb-item>
            </a-breadcrumb>
            <a-layout-content :style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }">
              Content
            </a-layout-content>
          </a-layout>
        </a-layout>
      </a-layout>
    </template>
    <script>
    export default {
      data () {
        return {
          collapsed: false,
        }
      },
    }
    </script>
    
    <style>
    #components-layout-demo-top-side-2 .logo {
      width: 120px;
      height: 31px;
      background: rgba(255,255,255,.2);
      margin: 16px 28px 16px 0;
      float: left;
    }
    </style>
    

    4.顶部-侧边布局

    在这里插入图片描述
    拥有顶部导航及侧边栏的页面,多用于展示类网站。

    <template>
      <a-layout id="components-layout-demo-top-side">
        <a-layout-header class="header">
          <div class="logo" />
          <a-menu
            theme="dark"
            mode="horizontal"
            :defaultSelectedKeys="['2']"
            :style="{ lineHeight: '64px' }"
          >
            <a-menu-item key="1">nav 1</a-menu-item>
            <a-menu-item key="2">nav 2</a-menu-item>
            <a-menu-item key="3">nav 3</a-menu-item>
          </a-menu>
        </a-layout-header>
        <a-layout-content style="padding: 0 50px">
          <a-breadcrumb style="margin: 16px 0">
            <a-breadcrumb-item>Home</a-breadcrumb-item>
            <a-breadcrumb-item>List</a-breadcrumb-item>
            <a-breadcrumb-item>App</a-breadcrumb-item>
          </a-breadcrumb>
          <a-layout style="padding: 24px 0; background: #fff">
            <a-layout-sider width="200" style="background: #fff">
              <a-menu
                mode="inline"
                :defaultSelectedKeys="['1']"
                :defaultOpenKeys="['sub1']"
                style="height: 100%"
              >
                <a-sub-menu key="sub1">
                  <span slot="title"><a-icon type="user" />subnav 1</span>
                  <a-menu-item key="1">option1</a-menu-item>
                  <a-menu-item key="2">option2</a-menu-item>
                  <a-menu-item key="3">option3</a-menu-item>
                  <a-menu-item key="4">option4</a-menu-item>
                </a-sub-menu>
                <a-sub-menu key="sub2">
                  <span slot="title"><a-icon type="laptop" />subnav 2</span>
                  <a-menu-item key="5">option5</a-menu-item>
                  <a-menu-item key="6">option6</a-menu-item>
                  <a-menu-item key="7">option7</a-menu-item>
                  <a-menu-item key="8">option8</a-menu-item>
                </a-sub-menu>
                <a-sub-menu key="sub3">
                  <span slot="title"><a-icon type="notification" />subnav 3</span>
                  <a-menu-item key="9">option9</a-menu-item>
                  <a-menu-item key="10">option10</a-menu-item>
                  <a-menu-item key="11">option11</a-menu-item>
                  <a-menu-item key="12">option12</a-menu-item>
                </a-sub-menu>
              </a-menu>
            </a-layout-sider>
            <a-layout-content :style="{ padding: '0 24px', minHeight: '280px' }">
              Content
            </a-layout-content>
          </a-layout>
        </a-layout-content>
        <a-layout-footer style="text-align: center">
          Ant Design ©2018 Created by Ant UED
        </a-layout-footer>
      </a-layout>
    </template>
    
    <style>
    #components-layout-demo-top-side .logo {
      width: 120px;
      height: 31px;
      background: rgba(255,255,255,.2);
      margin: 16px 28px 16px 0;
      float: left;
    }
    </style>
    

    5.上中下布局

    在这里插入图片描述
    最基本的『上-中-下』布局。
    一般主导航放置于页面的顶端,从左自右依次为:logo、一级导航项、辅助菜单(用户、设置、通知等)。通常将内容放在固定尺寸(例如:1200px)内,整个页面排版稳定,不受用户终端显示器影响;上下级的结构符合用户上下浏览的习惯,也是较为经典的网站导航模式。页面上下切分的方式提高了主工作区域的信息展示效率,但在纵向空间上会有一些牺牲。此外,由于导航栏水平空间的限制,不适合那些一级导航项很多的信息结构。

    <template>
      <a-layout id="components-layout-demo-top" class="layout">
        <a-layout-header>
          <div class="logo" />
          <a-menu
            theme="dark"
            mode="horizontal"
            :defaultSelectedKeys="['2']"
            :style="{ lineHeight: '64px' }"
          >
            <a-menu-item key="1">nav 1</a-menu-item>
            <a-menu-item key="2">nav 2</a-menu-item>
            <a-menu-item key="3">nav 3</a-menu-item>
          </a-menu>
        </a-layout-header>
        <a-layout-content style="padding: 0 50px">
          <a-breadcrumb style="margin: 16px 0">
            <a-breadcrumb-item>Home</a-breadcrumb-item>
            <a-breadcrumb-item>List</a-breadcrumb-item>
            <a-breadcrumb-item>App</a-breadcrumb-item>
          </a-breadcrumb>
          <div :style="{ background: '#fff', padding: '24px', minHeight: '280px' }">Content</div>
        </a-layout-content>
        <a-layout-footer style="text-align: center">
          Ant Design ©2018 Created by Ant UED
        </a-layout-footer>
      </a-layout>
    </template>
    <style>
    #components-layout-demo-top .logo {
      width: 120px;
      height: 31px;
      background: rgba(255,255,255,.2);
      margin: 16px 24px 16px 0;
      float: left;
    }
    </style>
    

    6.响应式布局

    在这里插入图片描述
    Layout.Sider 支持响应式布局。

    说明:配置 breakpoint 属性即生效,视窗宽度小于 breakpoint 时 Sider 缩小为 collapsedWidth 宽度,若将 collapsedWidth 设置为零,会出现特殊 trigger。

    <template>
      <a-layout id="components-layout-demo-responsive">
        <a-layout-sider
          breakpoint="lg"
          collapsedWidth="0"
          @collapse="onCollapse"
          @breakpoint="onBreakpoint"
        >
          <div class="logo" />
          <a-menu theme="dark" mode="inline" :defaultSelectedKeys="['4']">
            <a-menu-item key="1">
              <a-icon type="user" />
              <span class="nav-text">nav 1</span>
            </a-menu-item>
            <a-menu-item key="2">
              <a-icon type="video-camera" />
              <span class="nav-text">nav 2</span>
            </a-menu-item>
            <a-menu-item key="3">
              <a-icon type="upload" />
              <span class="nav-text">nav 3</span>
            </a-menu-item>
            <a-menu-item key="4">
              <a-icon type="user" />
              <span class="nav-text">nav 4</span>
            </a-menu-item>
          </a-menu>
        </a-layout-sider>
        <a-layout>
          <a-layout-header :style="{ background: '#fff', padding: 0 }" />
          <a-layout-content :style="{ margin: '24px 16px 0' }">
            <div :style="{ padding: '24px', background: '#fff', minHeight: '360px' }">
              content
            </div>
          </a-layout-content>
          <a-layout-footer style="textAlign: center">
            Ant Design ©2018 Created by Ant UED
          </a-layout-footer>
        </a-layout>
      </a-layout>
    </template>
    <script>
    export default {
      methods: {
        onCollapse(collapsed, type) {
          console.log(collapsed, type);
        },
        onBreakpoint(broken) {
          console.log(broken);
        }
      }
    }
    </script>
    
    <style>
    #components-layout-demo-responsive .logo {
      height: 32px;
      background: rgba(255,255,255,.2);
      margin: 16px;
    }
    </style>
    

    7.固定侧边栏

    在这里插入图片描述
    当内容较长时,使用固定侧边栏可以提供更好的体验。

    <template>
      <a-layout id="components-layout-demo-fixed-sider">
        <a-layout-sider :style="{ overflow: 'auto', height: '100vh', position: 'fixed', left: 0 }">
          <div class="logo"></div>
          <a-menu theme="dark" mode="inline" :defaultSelectedKeys="['4']">
            <a-menu-item key="1">
              <a-icon type="user" />
              <span class="nav-text">nav 1</span>
            </a-menu-item>
            <a-menu-item key="2">
              <a-icon type="video-camera" />
              <span class="nav-text">nav 2</span>
            </a-menu-item>
            <a-menu-item key="3">
              <a-icon type="upload" />
              <span class="nav-text">nav 3</span>
            </a-menu-item>
            <a-menu-item key="4">
              <a-icon type="bar-chart" />
              <span class="nav-text">nav 4</span>
            </a-menu-item>
            <a-menu-item key="5">
              <a-icon type="cloud-o" />
              <span class="nav-text">nav 5</span>
            </a-menu-item>
            <a-menu-item key="6">
              <a-icon type="appstore-o" />
              <span class="nav-text">nav 6</span>
            </a-menu-item>
            <a-menu-item key="7">
              <a-icon type="team" />
              <span class="nav-text">nav 7</span>
            </a-menu-item>
            <a-menu-item key="8">
              <a-icon type="shop" />
              <span class="nav-text">nav 8</span>
            </a-menu-item>
          </a-menu>
        </a-layout-sider>
        <a-layout :style="{ marginLeft: '200px' }">
          <a-layout-header :style="{ background: '#fff', padding: 0 }" />
          <a-layout-content :style="{ margin: '24px 16px 0', overflow: 'initial' }">
            <div :style="{ padding: '24px', background: '#fff', textAlign: 'center' }">
              ...
              <br />
              Really
              <br />...<br />...<br />...<br />
              long
              <br />...<br />...<br />...<br />...<br />...<br />...
              <br />...<br />...<br />...<br />...<br />...<br />...
              <br />...<br />...<br />...<br />...<br />...<br />...
              <br />...<br />...<br />...<br />...<br />...<br />...
              <br />...<br />...<br />...<br />...<br />...<br />...
              <br />...<br />...<br />...<br />...<br />...<br />...
              <br />...<br />...<br />...<br />...<br />...<br />
              content
            </div>
          </a-layout-content>
          <a-layout-footer :style="{ textAlign: 'center' }">
            Ant Design ©2018 Created by Ant UED
          </a-layout-footer>
        </a-layout>
      </a-layout>
    </template>
    <style>
    #components-layout-demo-fixed-sider .logo {
      height: 32px;
      background: rgba(255,255,255,.2);
      margin: 16px;
    }
    </style>
    

    8.固定头部

    在这里插入图片描述
    一般用于固定顶部导航,方便页面切换。

    <template>
      <a-layout id="components-layout-demo-fixed">
        <a-layout-header :style="{ position: 'fixed', zIndex: 1, width: '100%' }">
          <div class="logo" />
          <a-menu
            theme="dark"
            mode="horizontal"
            :defaultSelectedKeys="['2']"
            :style="{ lineHeight: '64px' }"
          >
            <a-menu-item key="1">nav 1</a-menu-item>
            <a-menu-item key="2">nav 2</a-menu-item>
            <a-menu-item key="3">nav 3</a-menu-item>
          </a-menu>
        </a-layout-header>
        <a-layout-content :style="{ padding: '0 50px', marginTop: '64px' }">
          <a-breadcrumb :style="{ margin: '16px 0' }">
            <a-breadcrumb-item>Home</a-breadcrumb-item>
            <a-breadcrumb-item>List</a-breadcrumb-item>
            <a-breadcrumb-item>App</a-breadcrumb-item>
          </a-breadcrumb>
          <div :style="{ background: '#fff', padding: '24px', minHeight: '380px' }">Content</div>
        </a-layout-content>
        <a-layout-footer :style="{ textAlign: 'center' }">
          Ant Design ©2018 Created by Ant UED
        </a-layout-footer>
      </a-layout>
    </template>
    <style>
    #components-layout-demo-fixed .logo {
      width: 120px;
      height: 31px;
      background: rgba(255,255,255,.2);
      margin: 16px 24px 16px 0;
      float: left;
    }
    </style>
    

    9.侧边布局

    在这里插入图片描述
    侧边两列式布局。页面横向空间有限时,侧边导航可收起。
    侧边导航在页面布局上采用的是左右的结构,一般主导航放置于页面的左侧固定位置,辅助菜单放置于工作区顶部。内容根据浏览器终端进行自适应,能提高横向空间的使用率,但是整个页面排版不稳定。侧边导航的模式层级扩展性强,一、二、三级导航项目可以更为顺畅且具关联性的被展示,同时侧边导航可以固定,使得用户在操作和浏览中可以快速的定位和切换当前位置,有很高的操作效率。但这类导航横向页面内容的空间会被牺牲一部份。

    API

    <Layout>
      <Header>header</Header>
      <Layout>
        <Sider>left sidebar</Sider>
        <Content>main content</Content>
        <Sider>right sidebar</Sider>
      </Layout>
      <Footer>footer</Footer>
    </Layout>
    

    Layout 布局容器

    参数 说明 类型 默认值
    class 容器 class string -
    style 指定样式 object -
    hasSider 表示子元素里有 Sider,一般不用指定。可用于服务端渲染时避免样式闪动 boolean -

    Layout.Header Layout.Footer Layout.Content API 与 Layout 相同

    Layout.Sider 侧边栏

    参数 说明 类型 默认值
    breakpoint 触发响应式布局的断点 Enum { 'xs', 'sm', 'md', 'lg', 'xl', 'xxl' } -
    class 容器 class string -
    collapsed(v-model) 当前收起状态 boolean -
    collapsedWidth 收缩宽度,设置为 0 会出现特殊 trigger number 80
    collapsible 是否可收起 boolean false
    defaultCollapsed 是否默认收起 boolean false
    reverseArrow 翻转折叠提示箭头的方向,当 Sider 在右边时可以使用 boolean false
    style 指定样式 object|string -
    theme 主题颜色 string: light dark dark
    trigger 自定义 trigger,设置为 null 时隐藏 trigger string|slot -
    width 宽度 number|string 200

    事件

    事件名称 说明 回调参数
    collapse 展开-收起时的回调函数,有点击 trigger 以及响应式反馈两种方式可以触发 (collapsed, type) => {}
    breakpoint 触发响应式布局断点时的回调 (broken) => {}

    breakpoint width

    {
    xs: ‘480px’,
    sm: ‘576px’,
    md: ‘768px’,
    lg: ‘992px’,
    xl: ‘1200px’,
    xxl: ‘1600px’,
    }

    展开全文
  • android:layout_width="match_parent" android:layout_height="match_parent" >
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <include layout="@layout/title" />

    </LinearLayout>

    titleone:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/bg"
        android:orientation="horizontal" >
        
        <Button 
            android:id="@+id/btnback"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_margin="7px"
            android:gravity="left"
            android:background="@drawable/cancel"
            />
        
        <TextView 
            android:id="@+id/txttitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:layout_gravity="center"
            android:textSize="50px"
            android:layout_weight="20"
            android:text="title"
            />
        
        <Button 
            android:id="@+id/btnclose"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="right"
            android:layout_margin="7px"
            android:layout_weight="1"
            android:background="@drawable/close"
            />


    </LinearLayout>


    java:

    package com.base.title;


    import com.example.test02.R;


    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.Window;
    import android.widget.Button;
    import android.app.Activity;


    public class TitleOneActivity extends Activity {


    Button btnBack;
    Button btnClose;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_title_one);
    btnBack = (Button)findViewById(R.id.btnback);
    btnClose = (Button)findViewById(R.id.btnclose);

    btnClose.setOnClickListener(new OnClickListener() {
    public void onClick(View arg0) {
    finish();
    }
    });
    }


    }


    效果图:


    展开全文
  • Android新特性介绍,ConstraintLayout完全解析

    万次阅读 多人点赞 2017-02-03 09:14:39
    今天给大家带来2017年的第一篇文章,这里先祝大家新年好。 本篇文章的主题是ConstraintLayout。其实ConstraintLayout是Android Studio 2.2中主要的新增功能之一,也是Google在去年的I/O大会上重点宣传的一个功能。...
  • Layout

    2019-05-28 13:42:30
    触摸按键设计Layout IC要放在PAD的中央,保证左右PAD走线最短和对称 PAD到IC的连线越短越好、线径使用最小线宽、走线不要和PAD同一层 触摸PAD的背面PCB不能走线(时钟) PAD旁边和背面不要不要铺地,如果需要...
  • Vlayout使用详细介绍

    千次阅读 2018-01-08 19:16:07
    Vlayout使用详细介绍 目录介绍 1.Vlayout简单介绍 2.主要功能介绍 2.1 主要功能的思维导图 2.2 主要功能说明 .使用方法与案例 3.1 初始化 3.2 设置回收复用池 ...4.1 VirtualLayoutAdapte
  • Unity/Auto Layout -- 理解Layout Elements(布局元素)

    万次阅读 多人点赞 2018-03-13 17:11:59
    前言 在UGUI1中,Canvas下的每个GameObject都会自动添加 Rect Transform 组件来控制自身的位置和大小。通常情况下,基于Rect Transform的布局系统已经足够灵活,可以方便地满足大部分UI布局的需要。...
  • R语言中layout()函数的用法

    万次阅读 多人点赞 2018-04-19 09:49:34
    R语言中layout()函数的用法
  • plt.tight_layout()

    万次阅读 多人点赞 2018-11-16 15:12:19
    tight_layout会自动调整子图参数,使之填充整个图像区域。这是个实验特性,可能在一些情况下不工作。它仅仅检查坐标轴标签、刻度标签以及标题的部分。 使用之前: 使用之后: 参考:...
  • ConstraintLayout 完全解析 快来优化你的布局吧

    万次阅读 多人点赞 2017-09-17 17:06:43
    本文已在我的公众号hongyangAndroid原创首发。 转载请标明出处: ... 本文出自张鸿洋的博客 本文已在我的公众号hongyangAndroid原创首发,...一、概述ConstraintLayout出现有一段时间了,不过一直没有特别去关注,
  • 有很多blog已经写的很详细了: 贴上他们的地址: Android ConstraintLayout百分比布局-适配终结者(基本适配所有机型) ConstraintLayout在项目中实践与总结 ...app:layout_constraintVertical_bias="1" ...
  • ConstraintLayout 属性详解 和Chain的使用

    万次阅读 多人点赞 2017-05-24 18:04:09
    小伙伴们好久不见,我又回来啦。 说实话这篇文章写的算是比较晚了,距离`ConstraintLayout`出现至今已经有一年...且自AS2.3起创建新的`Activity`,默认的layout根布局就是`ConstraintLayout`。 所以再不学习就真的晚了。
  • Android ConstraintLayout使用

    万次阅读 2018-10-15 21:42:46
    ConstraintLayout 翻译为 约束布局,也有人把它称作 增强型的相对布局,由 2016 年 Google I/O 推出。扁平式的布局方式,无任何嵌套,减少布局的层级,优化渲染性能。从支持力度而言,将成为主流布局样式,完全代替...
  • 心血来潮想用ConstraintLayout写一个弹出布局,写到怎么让两个控件平分现有宽度时看了下ConstraintLayout有个layout_constraintHorizontal_weight属性,这不正是自己想要的。 但是添加此代码后一直没效果,尝试很多...
  • 哲♂学三幻神带你学习ConstraintLayout(约束布局)标签(空格分隔): Tutorial-AndroidConstraintLayout 是什么 ConstraintLayout(约束布局) 其实已经不算什么新东西了,很多同学应该知道 或听过这个东西。人嘛,...
  • layout_constraintDimensionRatio属性 <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" ...
  • 注:以下结论由测试推测得到,仅仅是结果表现上合理,...ConstraintLayout layout_constraintDimensionRatio 可以设置一个前缀 w或h, 根据官方说法 The ratio can be expressed either as: a float value, rep...
  • ConstraintLayout

    千次阅读 2016-10-09 15:41:23
    android studio升级到stable 2.2之后,发现还有了个ConstraintLayout。看名字就是约束布局,用各种约束来确定widget的展示。该ConstraintLayout最低支持API 9。 看preview,也是各种线条,感觉很高端的样子。。。...
  • 今天在使用app:layout_constraintHorizontal_bias属性的时候遇到点小疑问,研究了一会儿才知晓bias值的意义:即bias值=子View左相关的长度/(子View左相关的长度+其右相关的长度),默认值为0.5。在此记录并分享以下两...
  • 则app:layout_constraintDimensionRatio="w,2:1"这行代码可以理解为以控件高度为基准,宽度的数值:高度的数值=2:1,即这里的宽度为200dp。效果图如下: 如果把layout_constraintDimensionRatio的值换成h,2:1,...
  • ConstraintLayout 这是一个约束布局,可以尽可能的减少布局的嵌套。有一个属性特别好用,可以用来动态限制宽或者高app:layout_constraintDimensionRatio 关于app:layout_constraintDimensionRatio参数 app:layout_...
  • Layout新姿势—ConstraintLayout。 突然发现as的创建新项目时,导入的默认布局是个新名词——ConstraintLayout。 这个新姿势, 感觉有必要搞一搞,转载了郭林大神这篇文章,撸起来吧~~~~ 原文:...
  • Android Studio的默认布局就是ConstraintLayout,而对于初学者来说LinearLayout布局用起来比较方便如果想将其默认布局改为LinearLayout 首先找到安装AS路径的安装路径,然后根据以下目录 Android Studio\plugins\...
  • ConstraintLayout是Android Studio 2.2中主要的新增功能之一,方便开发者使用图形化界面来完成UI布局,减少布局嵌套。更多的使用方法,可以...compile'com.android.support.constraint:constraint-layout:1.0.0-b...
  • 本人水平有限,如有不当之处,请谅解我在网上看了一些关于约束布局(ConstraintLayout)的文章,说约束布局可以减少嵌套,使用更方便,所以就实战了一下,看看约束布局如何实现LinearLayout和RelativeLayout的常用...
  • Android ConstraintLayout布局详解

    千次阅读 2017-10-21 14:04:39
    前言之前在使用Android Studio新建项目的时候,发现MainActivity的默认布局从RelativeLayout变成了ConstraintLayout。当时就对这个ConstraintLayout很好奇,就研究了一下。...Constraint Layout是Google在2016年的
  • ConstraintLayout动画入门

    千次阅读 2018-11-02 14:06:18
    前面有篇文章简单介绍了一下ConstraintLayout,如果有不熟的地方,可以自行查看。这里主要介绍一下ConstraintLayout可以实现的动画。 具体什么样的呢? 我们先看一个复杂一点的dome: 这里的ConstraintLayout动画...
  • android五花八门品类众多尺寸各异的屏幕,一直是产品经验和开发人员的心中难以解开的疙瘩,像素,DP,英寸各种的不方便。面对竞争激烈的APP市场,界面平庸了不出容易出彩,界面特殊了又会带来适配方面的难题。...
  • ConstraintLayout是谷歌推出的一个新布局,字面意思是约束布局,距离发布已经有一段时间了,下面会有一个复杂布局的代码对比。 对于ConstraintLayout,有篇文章写了关于它的性能优势:解析ConstraintLayout的性能...

空空如也

1 2 3 4 5 ... 20
收藏数 1,024,523
精华内容 409,809
关键字:

layout