当前位置:  编程技术>移动开发
本页文章导读:
    ▪系统设立更改时间onConfigurationChanged        系统设置更改时间onConfigurationChanged 在前一个例子中我们看到了屏幕方向的更改,事实上,当屏幕方向改变是,就会发生onConfigurationChanged()事件;虽然可以在更改方向是显示要更改的方向,但.........
    ▪ XCode适用快捷键        XCode实用快捷键 整理了常用的Xcode快捷键,工欲善其事,必先利其器。 新建项目 command+shift+n 新建文件 command+n 新建空文件 command+control+n 打开 command+o 关闭窗口 command+w 保存所有文件 command.........
    ▪ 顶部有一排旋钮,最底下还有FooterView的ListView页面       顶部有一排按钮,最底下还有FooterView的ListView页面 先上效果图:下面详细说说这个页面是怎么做出来的:1、这个页面最下方可以看到一个TAB页签,分别是“主页”、“提及”等等,这个.........

[1]系统设立更改时间onConfigurationChanged
    来源: 互联网  发布时间: 2014-02-18
系统设置更改时间onConfigurationChanged

在前一个例子中我们看到了屏幕方向的更改,事实上,当屏幕方向改变是,就会发生onConfigurationChanged()事件;虽然可以在更改方向是显示要更改的方向,但是并无法取得更改后的宽高或更改后的结果,此时,就必须通过onConfigurationChanged()的心事事件进行处理。

onConfigurationChanged()方法是当系统发生系统设置改变之后所触发的事件,其中唯一的传入参数为Configuration对象,出来可以捕捉屏幕设置更改事件之外,也可扑捉其他系统设置更改事件,如隐藏键盘或打开键盘等。

public class EX05_23 extends Activity
{
  private TextView mTextView01;
  private Button mButton01;
  
  /* 屏幕宽高 */
  private int intScreenH,intScreenW;
  
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    
    /* 声明Display对象,以取得屏幕宽高 */
    final Display defaultDisplay = getWindow().getWindowManager().getDefaultDisplay();
    intScreenH= defaultDisplay.getHeight();
    intScreenW = defaultDisplay.getWidth();
    
    mButton01 = (Button)findViewById(R.id.myButton1); 
    mTextView01 = (TextView)findViewById(R.id.myTextView1);
    mTextView01.setText(Integer.toString(intScreenW)+"x"+Integer.toString(intScreenH));
    
    /* 当宽>高,表示为横式显示 */
    if(intScreenW > intScreenH)
    {
      /* Landscape */
      mButton01.setText(R.string.str_button2);
    }
    else
    {
      /* Portrait */
      mButton01.setText(R.string.str_button1);
    }
    
    /* 按钮事件处理切换宽高 */
    mButton01.setOnClickListener(new Button.OnClickListener()
    {
      @Override
      public void onClick(View v)
      {
        // TODO Auto-generated method stub
        intScreenH= defaultDisplay.getHeight();
        intScreenW = defaultDisplay.getWidth();
        
        /* 如果为Landscape */
        if(intScreenW > intScreenH)
        {
          /* Landscape => Portrait */
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
        else
        {
          /* Portrait => Landscape */
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }
        
        /* 再一次取得屏幕宽高 */
        intScreenH= defaultDisplay.getHeight();
        intScreenW = defaultDisplay.getWidth();
        mTextView01.setText(Integer.toString(intScreenW)+"x"+Integer.toString(intScreenH));
      }
    });
  }  
  
  @Override
  public void onConfigurationChanged(Configuration newConfig)
  {
    // TODO Auto-generated method stub
    
    /* 覆写onConfigurationChanged事件,捕捉当设定之后的值 */
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
    {
      /* 趁着事件发生之后,变更按钮上的文字 */
      mButton01.setText(R.string.str_button2);
      mMakeTextToast
      (
        getResources().getText(R.string.str_onConf_LANDSCAPE).toString(),
        false
      );
    }
    
    /* 须设定configChanges属性才能捕捉onConfigurationChanged */
    if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
    {
      mButton01.setText(R.string.str_button1);
      mMakeTextToast
      (
        getResources().getText(R.string.str_onConf_PORTRAIT).toString(),
        false
      );
    }
    
    if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO)
    {
     
    }
    super.onConfigurationChanged(newConfig);
  }
  
  public void mMakeTextToast(String str, boolean isLong)
  {
    if(isLong==true)
    {
      Toast.makeText(EX05_23.this, str, Toast.LENGTH_LONG).show();
    }
    else
    {
      Toast.makeText(EX05_23.this, str, Toast.LENGTH_SHORT).show();
    }
  }
}

 必须要在Activity里设置configChanges属性,以作为系统设置更改时要扑捉的事件,除此之外,还需要获得系统设置更改的权限(<uses-permission android:name="android.permission.CHANGE_CONFIGURATION"></uses-permission>)

<application
    android:icon="@drawable/icon"
    android:label="@string/app_name">
    <!-- 必須設定activity的configChanges屬性 -->
    <activity
      android:name=".EX05_23"
      android:label="@string/app_name"
      android:configChanges="orientation|keyboard">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
  </application>
  <uses-sdk android:minSdkVersion="8" />
  <!-- 必須設定CHANGE CONFIGURATION權限 -->
  <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"></uses-permission>

 


    
[2] XCode适用快捷键
    来源: 互联网  发布时间: 2014-02-18
XCode实用快捷键

整理了常用的Xcode快捷键,工欲善其事,必先利其器。

新建项目 command+shift+n
新建文件 command+n
新建空文件 command+control+n
打开 command+o
关闭窗口 command+w
保存所有文件 command+option+s
还原到保存时状态 command+u
创建快照 command+control+s (保存文件快照,以后可进行对比修改情况)
左缩进 command+[
右缩进 command+]
项目中查找 command+shift+F
查找下一个 command+g
查找上一个 command+shift+g
用选择的查找 command+e
go to line command+l
下一个填充 control+. 
填充列表 option+esc

显示拼写和语法 command+shift+;
检查拼写 command+;
打开头文件 command+shift+d 
切换头/源文件 command+option+上箭头
类浏览 command+shift+c

Bulid and Run 断点关 command+r
Build and Debug 断点开 command+y
下个Build警告或错误 command+=
前个Build警告或错误 command+shift+=

注释 command+/
文件首行 command+上箭头
文件末 command+下箭头
行首 command+左箭头
行末 command+右箭头
上一单词 option+左箭头
下一单词 option+右箭头

中间显示光标位置 control+l
方法组列表 control+2
删除此行光标前所有内容 control+delete

断点 command+option+b
当前行插入断点 command+\
Pause command+option+p
Step Into command+shift+i
Step Into Instruction command+option+shift+i
Step Over command+shift+o
Setp Over Instruction command+option+shift+o
Setp Out command+shift+t

查开发文档 command+option+click

  整理了一下Xcode快捷键,史上最全!
xcode相关:
关于xcode  可设
偏好设置 command+,
清空缓存 可设
隐藏xcode command+h
隐藏其它 command+option+h
显示全部 可设
退出xcode command+q

 

文件相关:
新建项目 command+shift+n
新建文件 command+n
新建空文件 command+control+n
打开 command+o
在新窗口中打开   command+option+o
快速打开 command+shift+d / command+shift+alt+d (不知区别是什么)
清空最近打开文件 可设
清空最近打开项目 可设
Get Info command+i
显示检查器? command+option+i  (效果和Get Info一样,不知区别)
关闭窗口 command+w
关闭所有窗口 command+option+w
关闭当前项目 command+control+w
关闭当前文件 command+shift+w
保存文件 command+s
保存所有文件 command+option+s
另存为 command+shift+s
复本另存为 command+option+shift+s
还原到保存时状态 command+u
创建快照 command+control+s (保存文件快照,以后可进行对比修改情况)
显示快照 可设 (File->Snapshots)
打印 command+p
编辑相关:
撤销 command+z
重复 command+shift+z
剪切 command+x
复制 command+c
粘贴 command+v
粘贴并匹配格式 command+option+shift+v
删除 可设
全选 command+a
复制(Duplicate) 可设
重构 command+shift+j (选中方法名)
转换为objc2.0 可设
=================字体====================
显示字体 command+t
粗体 可设
斜体 可设
下划线 可设
变大字号 可设
变小字号 可设
Kern相关 可设
Ligature相关 可设
Baseline相关 可设
显示颜色 可设
复制样式 command+option+c
粘贴样式 command+option+v
=================文本====================
左对齐 command+{
右对齐 command+}
居中 command+竖线 (不知竖线是哪个,没试出)
Justify                       可设(功能未知)
左缩进 command+[
右缩进 command+]
Show Ruler 可设(功能未知)
Copy Ruler command+control+c
Paste Ruler command+control+v
Balance 可设 (第一次,选中语句,第二次,选中方法体)
重置缩进 可设
=================查找==================== 
项目中查找 command+shift+F
在项目中查找选定文本 可设
查找 可设
查找替换 command+control+f
查找选定文本 可设
查找下一个 command+g
查找上一个 command+shift+g
隐藏查找栏 可设
替换 可设
替换全部 可设
替换并查找下一个 可设
替换并查找上一个 可设
用选择的查找 command+e
用选择的替换 command+control+e
跳到光标处 command+j
跳到定义 可设
=================排序====================
按名 可设
按类型 可设
========================================
添加书签 command+d
go to line command+l
下一个填充 control+. 
填充列表 option+esc
下一个占位符 control+/ (和tab相同)
Edit All in Scope command+control+t (功能未知)
================插入宏=================
c
c++
html
java
objective-c
宏规范
=================拼写====================
显示拼写和语法 command+shift+;
检查拼写 command+;
输入时检查拼写 可设
特殊符号 command+option+t
视图相关:
右上角详情搜索 command+option+f
缩放编辑窗口 command+shift+e
缩放编辑窗口满屏 command+option+shift+e
折叠 command+control+左箭头
屏开 command+control+右箭头
屏开所有 control+u
折叠方法 command+control+上箭头
展开方法 command+control+下箭头
折叠注释块 command+control+shift+上箭头
展开注释块 command+control+shift+下箭头
焦点跟随 command+option+control+f
==============信息提示====================
隐藏问题 command+shift+h
所有问题 可设
仅错误和警告 可设
仅错误 可设
仅Analyzer结果 可设
显示断点 可设
==================文本====================
tab设置 可设
是否自动换行显示 可设
行结束 可设
显示控制字符 command+shift+6
显示空格 可设
==============智能分组====================
所有文件  可设
Targets 可设
Exeutables 可设
书签 command+shift+m
Symbols 可设
搜索结果 可设
===================布局====================
显示导航栏 可设
隐藏状态栏 可设
显示收藏栏 可设
显示页数控制 可设
===========================================
前进 command+option+右箭头
下一文件 command+option+shift+右箭头
返回 command+option+左箭头
上一文件 command+option+shift+左箭头
切换头/源文件 command+option+上箭头
组树中定位 command+option+shift+上箭头
显示工具栏 可设
自定义工具栏 可设
 ===================项目====================
项目中标签切换 command+数字0
类浏览 command+shift+c
重命名项目 可设
新组 command+option+n
分组 command+option+g
撤销分组 command+option+shift+g
新建智能组 可设
添加项目 command+option+a
添加文件到项目 可设
新Target 可设
升级所有Targets 可设
升级当前Target到ipad 可设
================New Build Phase====================
没做测试不多介绍,只放出内容
New Copy Files Build Phase
New Run Script Build Phase
New Copy Headers Build Phase
New Copy Bundle Resources Build Phase
New Compile Sources Build Phase
New Link Binary With Libraries Build Phase
New Build Java Resources Build Phase
New Build Resource Manager Resources Build Phase
================================================
新的自定义可执行文件 可设
设置当前Target 为空 可设
Set Active Architecture 为空 可设
设置当前sdk 为空 可设
设置Build配置 为空 可设
Set Active Executable 为空 可设
编辑项目设置 可设
编辑当前Target command+option+e
编辑当前可执行文件 command+option+x
===================Build========================
Bulid Results command+shift+b
Bulid command+b
Build and Analyze command+shift+a
Build and Archive 可设
Build and Debug command+enter
Bulid and Run 断点关 command+r
Build and Debug 断点开 command+y
Clean command+shift+k
Clean All Targets 可设
下个Build警告或错误 command+=
前个Build警告或错误 command+shift+=
Compile command+k
Preprocess 可设
Show Assembly Code 可设
Touch 可设
=======================代码导航及编辑================
注释 command+/
文件首行 command+上箭头
文件末 command+下箭头
行首 command+左箭头
行末 command+右箭头
上一单词 option+左箭头
下一单词 option+右箭头
上一拆分单词 control+左箭头
下一拆分单词 control+右箭头
中间显示光标位置 control+l
方法组列表 control+2
删除前一单词 option+delete
删除此行光标前所有内容 control+delete
跨行选取 command+option+鼠标拖动


Run相关:

Debug command+option+enter
Run 断点关 command+option+r
Debug 断点开 command+option+y
Run with Performance Tool (Shark) 可设
Stop command+shift+enter
Attach to Process (Process ID) 可设
Debugger command+option+y
Mini Debugger command+control+左斜上箭头(不知咋按)
Console command+shift+r
Clear Console command+option+control+r
===================Show========================
断点 command+option+b
Expressions 可设
Global Variables 可设
Memory Browsers 可设
Shared Libraries 可设
===================Debugger Display========================
纵布局 可设
横布局 可设
Datatips 可设
Step Controls 可设
Source Only 可设
Source And Disassembly 可设
Disassembly 可设
===================Variables View========================
User Data Formatters
Show Type Column
Print Description to Console
Print Roots to Console
Print Referers to Console
Watch Variable
View Value as
Natural
Hexadecimal
OSType
Decimal
Unsigned Decimal
Octal
Binary
Edit Value
Edit Summary Format
View in Memory Browser
View in Window
View in Expressions Window
===============================================
停用断点 command+control+\
停止objc例外 可设
================Manage Brakpoints=================
当前行插入断点 command+\
Add Symbolic Breakpoint 可设
Add C++ Exception Breakpoint 可设
启用当前行断点 command+option+\
导入断点 可设
导出断点 可设
===============================================
Fix 可设
Pause command+option+p
Step Into command+shift+i
Step Into Instruction command+option+shift+i
Step Over command+shift+o
Setp Over Instruction command+option+shift+o
Setp Out command+shift+t
Next Thread command+option+control+上箭头
Previous Thread command+option+control+下箭头
Sync with Debugger 可设
Stop on Debugger()/DebugStr() 可设
Enable Guard Malloc 可设

Desing相关:
======================Class Model===================
Quick Model
Go to Declaration
Go to Definition
Go to Documentation
Add Comment
======================Data Model===================
Import
Add Model Version
Set Current Version
Add Entity
Add Attribute            command+control+a
Add Fetched Property
Add Relationship command+control+r
Add Fetch Request 
Copy Method Declarations to Clipboard
Copy Method Implementations to Clipboard
Copy Obj-C 2.0 Method Declarations to Clipboard
Copy Obj-C 2.0 Method Implementations to Clipboa
======================Mapping Model===================
Update Source Model
Update Destination Model
Add Missing Property Mappings
===================================================
Show Model Browser command+control+b
Collapse Compartments
Expand Compartments
Roll Up Compartments
Roll Down Compartments
======================Diagram=======================
Bring to Front command+control+shift+f
Send to Back command+control+shift+b
Align Top Edges
Align Bottom Edges
Align Left Edges
Align Right Edges
Align Vertical Centers
Align Horizontal Centers
Make Centered Colum
Make Centered Row
Make Same Width
Make Same Height
Size to Fit
Lock command+control+l
Unlock command+shift+control+l
Zoom in command+control++
Zoom Out command+control+-
Zoom to Fit command+control+=
Turn Grid On
Show Grid
Show Page Breaks
Force-Directed Layout command+control+g
Hierarchical Layout command+control+h
Window相关:
最小化 command+m
全部最小化 command+option+m
Zoom
Bring All to Front
Defaults
Organizer command+control+o
Activity 
Help相关:
开发文档 command+option+?
快速帮助 command+control+?
Xcode帮助 command+?
Welcome to Xcode
Xcode Quick Start
Xcode Release Notes
Find Documentation for Selected Text
Open man Page

转自: http://www.cnblogs.com/ylucy


    
[3] 顶部有一排旋钮,最底下还有FooterView的ListView页面
    来源: 互联网  发布时间: 2014-02-18
顶部有一排按钮,最底下还有FooterView的ListView页面
先上效果图:


下面详细说说这个页面是怎么做出来的:

1、这个页面最下方可以看到一个TAB页签,分别是“主页”、“提及”等等,这个是一个在底部的TAB分页样式,在上一篇博客中已经介绍了

2、这个页面就是“主页”这个子页面,是嵌入到上面说的TAB布局中的。由3个部分组成,分别是最上面的状态栏(包含2个按钮,和一个文本区)、中间的列表、最下方的“更多”按钮(当更多按钮点击时,会加载更多数据,并且出现LOADING提示)
<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="fill_parent" android:layout_height="fill_parent">

	<LinearLayout android:background="#ffffffff"
		android:layout_width="fill_parent" android:layout_height="fill_parent"
		android:orientation="vertical" />

	<include android:id="@+id/head_line" layout="@layout/head_line"
		android:layout_width="fill_parent" android:layout_height="wrap_content" />
	<ListView android:cacheColorHint="#00000000" android:id="@id/android:list"
		android:layout_width="fill_parent" android:fastScrollEnabled="false"
		android:layout_height="wrap_content" android:paddingTop="45.0dip"
		android:fadingEdge="none" android:paddingBottom="50.0dip"
		android:divider="@drawable/list_divider" android:clipToPadding="false" />

</FrameLayout>

上面这段代码,就生成了列表,和顶部的状态栏。顶部的状态栏是通过<include>标签引入的
<RelativeLayout android:background="@drawable/header"
	android:layout_width="fill_parent" android:layout_height="wrap_content"
	xmlns:android="http://schemas.android.com/apk/res/android">

	<Button android:id="@+id/top_btn_left" android:textColor="@color/button_text_selector"
		android:background="@drawable/top_refresh_selector"
		android:layout_width="wrap_content" android:layout_height="wrap_content"
		android:layout_marginLeft="12.0dip" android:layout_alignParentLeft="true"
		android:layout_centerVertical="true" />

	<Button android:id="@+id/top_btn_right" android:textColor="@color/button_text_selector"
		android:background="@drawable/top_edit_selector" android:layout_width="wrap_content"
		android:layout_height="wrap_content" android:layout_marginRight="12.0dip"
		android:layout_alignParentRight="true" android:layout_centerVertical="true" />

	<TextView android:id="@+id/top_title" android:textSize="22.0sp"
		android:textColor="@color/head_line_text" android:ellipsize="middle"
		android:gravity="center_horizontal" android:layout_width="wrap_content"
		android:layout_height="wrap_content" android:text="@string/user_name"
		android:singleLine="true" android:layout_toLeftOf="@id/top_btn_right"
		android:layout_toRightOf="@id/top_btn_left"
		android:layout_centerInParent="true"
		android:layout_alignWithParentIfMissing="true" />

</RelativeLayout>

是一个最简单的横向排列布局,就不用多介绍了

3、然后是这个FooterView是怎么添加进来的,看代码
@Override
	protected void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.home);
		setUpViews();// 设置视图
		setUpListeners();// 设置侦听器
		fillInitData();// 填充初始化数据

	}

	/**
	 * 设置视图
	 */
	private void setUpViews() {

		listView = getListView();// 得到ListView
		listFooter = (LinearLayout) LayoutInflater.from(this).inflate(
				R.layout.list_footer, null);
		listView.addFooterView(listFooter);// 添加FooterView
		
		more = (TextView) findViewById(R.id.more);
		loading = (LinearLayout) findViewById(R.id.loading);

	}

通过ListView.addFooterView()方法,来给列表添加一个FooterView,而这个FooterView,也是来自一个layout xml
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout android:layout_width="fill_parent"
	android:layout_height="wrap_content" android:minHeight="?android:listPreferredItemHeight"
	xmlns:android="http://schemas.android.com/apk/res/android">

	<TextView android:textSize="16.0sp" android:textColor="#ff545454"
	android:gravity="center" android:id="@+id/more" android:layout_width="fill_parent"
	android:layout_height="fill_parent" android:text="@string/more" />

	<LinearLayout android:gravity="center"
		android:layout_gravity="center" android:orientation="horizontal"
		android:id="@+id/loading" android:layout_width="fill_parent"
		android:layout_height="fill_parent">

		<ProgressBar android:layout_gravity="center_vertical"
			android:id="@+id/footprogress" android:layout_width="wrap_content"
			android:layout_height="wrap_content" android:indeterminateBehavior="repeat"
			 />

		<TextView android:textColor="#ff000000" android:gravity="left|center"
			android:padding="3.0px" android:layout_width="wrap_content"
			android:layout_height="wrap_content" android:text="@string/loading" />

	</LinearLayout>

</LinearLayout>

这个FooterView包含一个“更多”的文本框,和一个“读取中”文本框。这里我没弄明白的是,为什么一开始默认只会显示“更多”,读取栏不会显示出来,需要
more.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				more.setVisibility(View.GONE);
				loading.setVisibility(View.VISIBLE);
			}
		});

这样做,才能让“更多”按钮消失,显示出“读取中”,希望知道的朋友给我讲解一下。

通过上面的代码,就可以做出效果图里的页面了。

最后谈一下感想,我感觉android的布局还是比较难的,除了对各种View和ViewGroup对象的特性和API都要比较熟悉之外,还要对xml里各种android:xxx的属性都比较清楚,才能做出各种布局和样式的页面来。

不像CSS就比较简单,基本上只要弄明白BOX模型和组件嵌套的原理,以及float等比较特殊的处理,就可以做出想要的页面了,而且CSS的属性又比较少,大概就30多个,多用几次就十分熟练了。android光是android:xxx就有好多,我现在也没熟练掌握几个,还得多加油才行

    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3