1. android锛氭渶鍏ㄩ溃镄 Webview 璇﹁В
WebView鏄涓涓锘轰簬webkit寮曟搸銆佸𪾢鐜皐eb椤甸溃镄勬带浠躲
涓鑸𨱒ヨ碬ebview鍙鍗旷嫭浣跨敤锛屽彲镵斿悎鍏跺瓙绫讳竴璧蜂娇鐢锛屾墍浠ユ帴涓嬫潵锛屾垜浼氢粙缁嶏细
甯歌佺敤娉曪细Back阌鎺у埗缃戦〉钖庨
閰岖疆姝ラ1锛氭坊锷犺块梾缃戠粶𨱒冮檺 锛圆ndroidManifest.xml锛
閰岖疆姝ラ2锛氱敓鎴愪竴涓猈ebView缁勪欢锛堟湁涓ょ嶆柟寮忥级
閰岖疆姝ラ3锛氲繘琛岄厤缃-鍒╃敤WebSettings瀛愮被 锛埚父瑙佹柟娉曪级
甯歌佺敤娉曪细璁剧疆WebView缂揿瓨
娉ㄦ剰锛 姣忎釜 Application 鍙璋幂敤涓娆 WebSettings.setAppCachePath()锛学ebSettings.setAppCacheMaxSize()
甯歌佹柟娉1锛歴houldOverrideUrlLoading()
甯歌佹柟娉2锛歰nPageStarted()
甯歌佹柟娉3锛歰nPageFinished()
甯歌佹柟娉4锛歰nLoadResource()
甯歌佹柟娉5锛歰nReceivedError锛堬级
甯歌佹柟娉6锛歰nReceivedSslError()
甯歌佹柟娉1锛 onProgressChanged锛堬级
甯歌佹柟娉2锛 onReceivedTitle锛堬级
鍏蜂綋璇风湅鎴戝啓镄勬枃绔 Android WebView涓嶫S镄勪氦浜掓柟寮 链鍏ㄩ溃姹囨
3.4.1 涓嶅湪xml涓瀹氢箟 Webview 锛岃屾槸鍦ㄩ渶瑕佺殑镞跺椤湪Activity涓鍒涘缓锛屽苟涓擟ontext浣跨敤 getApplicationgContext()
3.4.2 鍦 Activity 阌姣侊纸 WebView 锛夌殑镞跺欙纴鍏堣 WebView 锷犺浇null鍐呭癸纴铹跺悗绉婚櫎 WebView锛屽啀阌姣 WebView锛屾渶钖庣疆绌恒
姝ラ1锛氭坊锷犺块梾缃戠粶𨱒冮檺
AndroidManifest.xml
姝ラ2锛氢富甯冨眬
activity_main.xml
姝ラ3锛氭牴鎹闇瑕佸疄鐜扮殑锷熻兘浠庤屼娇鐢ㄧ浉搴旂殑瀛愮被鍙婂叾鏂规硶锛堟敞閲婂緢娓呮氢简锛
MainActivity.java
2. Android-EditView文本编辑控件详解
EditView 是Android开发当中运用到最多的控件之一,主要用户界面上的输入框。
View --> TextView --> EditView 。
1.设置提示文本:
2.设置hint提示文字颜色:
3.设置输入文本后的文字颜色:
4.设置输入文本后的字体大小:
5.设置输入文本后的字体样式,bold(加粗),italic(倾斜),normal(默认是正常字体)。
6.设置被选中字体的颜色.默认为 Theme 主题中的 “colorAccent”的颜色。
7.设置被光标的颜色.默认为 Theme 主题中的 “colorAccent”的颜色。
8.设置文本的水平缩放系数。
9.设置hint提示文本的字体.normal(默认)\monospace\sans\serif。
10.设置EditText背景."@null"设置背景为透明.当我们设置背景后,EditText的下划线就会消失。
11.设置文本的颜色,字体,大小和样式。
12.设置只接收指定的文本内容,适合只能输出特定内容的需求。
13.设置文本的类型,用于帮助输入法显示合适的键盘类型。
14.设置EditText最多接受的文本的个数:
15.设置EditText显示的行数,设置两行就显示两行,即使第二行没有数据。
16.设置行间距的倍数. 如设置成1.5倍。
17.设置右下角IME动作与编辑框相关的动作,如actionDone右下角将显示一个“完成”,而不设置默认是一个回车符号.
3. Android 布局优化之 ViewStub、 include、merge
文章、布局优化神器 include 、merge、ViewStub 标签详解
Tips:
include 标签使用:
//include_test.xml
<?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:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/textview"
android:textSize="24sp"/>
<EditText
android:id="@+id/editText"
android:hint="@string/divide"
android:layout_width="300dp"
android:layout_height="wrap_content"/>
</LinearLayout>---------------------------------------------------------------
//include_text_relative
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="TextView_Relative"
android:textSize="24sp"/>
<EditText
android:id="@+id/editText"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_below="@+id/textView"
android:hint="@string/divide"/>
</RelativeLayout>
---------------------------------------------------------------
//include_toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/tb_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#00f"
app:theme="@style/AppTheme"
app:title="这是一个 ToolBar"app:titleTextColor="@android:color/white"/>
<?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="match_parent"
android:orientation="vertical"
>
<!--测试 layout 和<include>都设置 ID 的情况-->
<include
android:id="@+id/tb_toolbar"
layout="@layout/include_toolbar"/>
<!--如果只有单个 include 这样写就可以,加载的布局的子 View,直接 findViewByID 就能找
到-->
<include layout="@layout/include_text"/>
<!--如果有多个 include,需要添加 ID 属性-->
<include
android:id="@+id/include_text1"
layout="@layout/include_text"/>
<!--这个 layout 用 RelativeLayout 实现-->
<!--如果要使用 layout_margin 这样的属性,要同时加上 layout_w/h 属性,不然没反应-->
<include
android:id="@+id/include_text2"
layout="@layout/include_text_relative"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="50dp"/>
</LinearLayout>
private void initView() {
//如果 include 布局根容器和 include 标签中的 id 设置的是不同的值,这里获取的
mToolbar 值将为 nullToolbar mToolbar = (Toolbar) findViewById(R.id.tb_toolbar);
setSupportActionBar(mToolbar);
//普通 include 标签用法,直接拿子 View 属性实现
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText("不加 ID 实现的 include 标签");
//多个 include 标签用法,添加 ID,findViewByID 找到 layout,再找子控件
View view_include = findViewById(R.id.include_text1);
TextView view_include_textView = (TextView) view_include.findViewById(R.id.textView);
view_include_textView.setText("加了 ID 实现的 include 标签");
//多个 include 标签用法,添加 ID,findViewByID 找到 layout,再找子控件
View view_include_Relative = findViewById(R.id.include_text2);
TextView view_textView_relative =(TextView) view_include_Relative.findViewById(R.id.textView);
view_textView_relative.setText("加了 ID 实现的 include 标签(RelaviteLayout)");
}
include 标签 Demo 效果图
==include 使用注意==
merge标签主要用于辅助include标签,在使用include后可能导致布局嵌套过
多,多余的 layout 节点或导致解析变慢(可通过 hierarchy viewer 工具查看布
局的嵌套情况)官方文档说明:merge 用于消除视图层次结构中的冗余视图,例如根布局是
Linearlayout,那么我们又 include 一个 LinerLayout 布局就没意义了,反而会
减慢 UI 加载速度
merge 标签常用场景: .
根布局是 FrameLayout 且不需要设置 background 或 padding 等属性,可
以用merge代替,因为 Activity的 ContentView 父元素就是FrameLayout,
所以可以用 merge 消除只剩一个.
.某布局作为子布局被其他布局include时,使用merge当作该布局的顶节点,
这样在被引入时顶结点会自动被忽略,而将其子节点全部合并到主布局中.
.自定义 View 如果继承 LinearLayout(ViewGroup),建议让自定义 View 的
布局文件根布局设置成 merge,这样能少一层结点.
.merge 标签使用:
在 XML 布局文件的根布局如 RelativeLayout 直接改成 merge 即可
merge 标签使用前后 Hierarchy Viewer 截图
FrameLayout 替换 merge 前
FrameLayout 替换 merge 后
include 标签对应 layout 根布局 替换 merge 前
include 标签对应 layout 根布局 替换 merge 后
==merge 使用注意==
ViewStub 标签最大的优点是当你需要时才会加载,使用它并不会影响 UI 初始
化时的性能.各种不常用的布局像进度条、显示错误消息等可以使用 ViewStub
标签,以减少内存使用量,加快渲染速度.ViewStub 是一个不可见的,实际上是把
宽高设置为 0 的 View.效果有点类似普通的 view.setVisible(),但性能体验提高
不少
第一次初始化时,初始化的是 ViewStub View,当我们调用 inflate()或
setVisibility()后会被 remove 掉,然后在将其中的 layout 加到当前 view
hierarchy 中
ViewStub 官方文档链接
//官方例子
<ViewStub
android:id="@+id/stub_import"
<!--android:inflateId:重写 ViewStub 的父布局控件的 Id-->
android:inflatedId="@+id/panel_import"
< <!--android:layout:设置 ViewStub 被 inflate 的布局-->
android:layout="@layout/progress_overlay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
-------------------------------------------------//当你想加载布局时,可以使用下面其中一种方法:
((ViewStub)
findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub)
findViewById(R.id.stub_import)).inflate();
判断 ViewStub(做单例)是否已经加载过:
1. 如果通过 setVisibility 来加载,那么通过判断可见性即可;
2. 如果通过 inflate()来加载,判断 ViewStub 的 ID 是否为 null 来判断
(findViewById(…))
public class ViewStubActivity extends AppCompatActivity
implements View.OnClickListener, ViewStub.OnInflateListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);setContentView(R.layout.activity_view_stub);
}
private View networkErrorView;
private void showNetError() {
// not repeated infalte
if (networkErrorView != null) {
//setVisibility()方式加载布局,加载次数不限
networkErrorView.setVisibility(View.VISIBLE);
return;
}
//inflate()方式加载布局,只能加载一次
ViewStub stub = (ViewStub)
findViewById(R.id.network_error_layout);
stub.setOnInflateListener(this);networkErrorView = stub.inflate();
Button networkSetting = (Button)
networkErrorView.findViewById(R.id.network_miss);
networkSetting.setOnClickListener(this);
Button refresh = (Button)
findViewById(R.id.network_refresh);
refresh.setOnClickListener(this);
}
private void showNormal() {
if (networkErrorView != null) {
networkErrorView.setVisibility(View.GONE);
}
}
public void show(View view) {showNetError();
}
public void refresh(View view) {
showNormal();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.network_miss:
Toast.makeText(this, "network_miss",
Toast.LENGTH_SHORT).show();
break;
case R.id.network_refresh:
Toast.makeText(this, "network_refresh",
Toast.LENGTH_SHORT).show();break;
}
}
/**
*
* @param stub 当前待 inflate 的 ViewStub 控件
* @param inflated 当前被 inflate 的 View 视图
*/
@Override
public void onInflate(ViewStub stub, View inflated) {
}
}
ViewStub 标签 Demo 效果图:
ViewStub 标签使用前后 Hierarchy Viewer 截图
ViewStub 标签使用前:
ViewStub 标签使用后:
==ViewStub 标签使用注意==
扩展:
Space 组件
在 ConstraintLayout 出来前,我们写布局都会使用到大量的 margin 或
padding,但是这种方式可读性会很差,加一个布局嵌套又会损耗性能
鉴于这种情况,我们可以使用space,使用方式和View一样,不过主要用来占位置,
不会有任何显示效果
4. 如何学习Android5.0 下 新的 webview 的实现
Android webview使用详解
1. 打开网页时不调用系统浏览器, 而是在本WebView中显示:
mWebView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
2. 通过java代码调用javascript
WebSettings webSettings = mWebView .getSettings();
webSettings.setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new Object() {
public void clickOnAndroid() {
mHandler.post(new Runnable() {
public void run() {
webview.loadUrl("javascript:wave()");
}
});
}
}, "demo");
3. 按返回键时, 不退出程序而是返回上一浏览页面:
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
4. 打开页面时, 自适应屏幕:
WebSettings webSettings = mWebView .getSettings();
webSettings.setUseWideViewPort(true);//设置此属性,可任意比例缩放
webSettings.setLoadWithOverviewMode(true);
5. 便页面支持缩放:
WebSettings webSettings = mWebView .getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setBuiltInZoomControls(true);
webSettings.setSupportZoom(true);
6.如果webView中需要用户手动输入用户名、密码或其他,则webview必须设置支持获取手势焦点。
webview.requestFocusFromTouch();
7.WebView 加载界面主要调用三个方法:LoadUrl、LoadData、LoadDataWithBaseURL.
1、LoadUrl 直接加载网页、图片并显示.(本地或是网络上的网页、图片、gif)
2、LoadData 显示文字与图片内容 (模拟器1.5、1.6)
3、LoadDataWithBase 显示文字与图片内容(支持多个模拟器版本)
8.WebSettings 的常用方法介绍
setJavaScriptEnabled(true); //支持js
setPluginsEnabled(true); //支持插件
setUseWideViewPort(false); //将图片调整到适合webview的大小
setSupportZoom(true); //支持缩放
setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); //支持内容重新布局
supportMultipleWindows(); //多窗口
setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存
setAllowFileAccess(true); //设置可以访问文件
setNeedInitialFocus(true); //当webview调用requestFocus时为webview设置节点
webview webSettings.setBuiltInZoomControls(true); //设置支持缩放
(true); //支持通过JS打开新窗口
setLoadWithOverviewMode(true); // 缩放至屏幕的大小
setLoadsImagesAutomatically(true); //支持自动加载图片
9.WebViewClient 的方法全解
doUpdateVisitedHistory(WebView view, String url, boolean isReload) //(更新历史记录)
onFormResubmission(WebView view, Message dontResend, Message resend) //(应用程序重新请求网页数据)
onLoadResource(WebView view, String url) // 在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
onPageStarted(WebView view, String url, Bitmap favicon) //这个事件就是开始载入页面调用的,通常可以在这设定一个loading的页面,告诉用户程序在等待网络响应。
onPageFinished(WebView view, String url) //在页面加载结束时调用。同样道理,咱们知道一个页面载入完成,于是可以关闭loading 条,切换程序动作。
onReceivedError(WebView view, int errorCode, String description, String failingUrl)// (报告错误信息)
onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host,String realm)//(获取返回信息授权请求)
onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) //重写此方法可以让webview处理https请求。
onScaleChanged(WebView view, float oldScale, float newScale) // (WebView发生改变时调用)
onUnhandledKeyEvent(WebView view, KeyEvent event) //(Key事件未被加载时调用)
shouldOverrideKeyEvent(WebView view, KeyEvent event)//重写此方法才能够处理在浏览器中的按键事件。
shouldOverrideUrlLoading(WebView view, String url)
//在点击请求的是链接是才会调用,重写此方法返回true表明点击网页里面的链接还是在当前的webview里跳转,不跳到浏览器那边。这个函数咱们可以做很多操作,比如咱们读取到某些特殊的URL,于是就可以不打开地址,取消这个操作,进行预先定义的其他操作,这对一个程序是非常必要的。
5. Android 自定义控件 layout
Android 绘制流程
View :View主要执行layout方法,使用 serFrame 方法来设置本身 View 的四个顶点的位置,确定View本身的位置。
ViewGroup :ViewGroup主要执行onLayout方法,递归遍历所有子View,确定子View的位置。
我们来看ViewRootImpl中的 performLayout() 方法
看到这里,那host.getMeasuredWidth() / host.getMeasuredHeight()是什么?它是直接调用View中的方法,其实就是经过measure后的DecorView的测量宽度和高度。在 Android 自定义控件 measure 中有说明。
2.3.2.1 我们先来看ViewGroup中的 layout() 方法
ViewGroup里面的layout最终会调入到父类View中的layout,View的layout后面讲解。这里可以先告诉大家,最终会调用View的onLayout方法,而ViewGroup的onLayout是抽象方法,所以它的子类LinearLayout必须要实现。
2.3.2.2 我们再来看LinearLayout中的 onLayout() 方法。
2.3.2.3 挑一个纵向的吧,我们再来看LinearLayout中的 layoutVertical() 方法。
2.3.2.4 我们再来看LinearLayout中的 setChildFrame() 方法。
又一次回到了View的layout方法,接下来就看View分发的layout。
我们先来看View中的 layout() 方法。
我们先来看View中的 onLayout() 方法。
空空如也,其实View的布局由父容器决定,所以空实现是正常的,当然也可以在自定义View中进行更改。
《Android 视图模块 全家桶》
Android开发之自定义控件(二)---onLayout详解
自定义View Layout过程 - 最易懂的自定义View原理系列(3)
6. Android UI | View 的绘制流程详解
上一篇文章讲解了,从setContentView方法到了解View是如何绘制的: 传送门
在这篇博客讲述了, 在ViewRootImpl类中performTraversals方法中具体的绘制过程,其中里面就有 performMeasure()、performLayout()、performDraw() 三个方法的调用, 那么要了解View 的测量、布局、绘制,就分别跟这三个方法有关系。
先来看看performMeasure()方法的调用过程
先看performMeasure方法,这个方法有两个参数,都是通过getRootMeasureSpec()方法计算得到
这里有一个关键类MeasureSpec,在这里需要了解下这个类的原理。
这里要感谢 这位博主 ,他讲述的很清晰,我自己动手测算了,很容易理解。大概就是用一个数字通过高位记录Mode,地位记录size的方式,记录两个数据,都是通过一个掩码做位移运算得来。就是说这个变量(measureSpec)的值可以通过掩码分别得到测量mode 和 测量size。
继续查看performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);方法:
这里mView是DecorView对象,那么他调用的实际上是View的measure方法,查询DecorView和FrameLayout都没有measure方法,所以他调用的是View的measure方法
DecorView.onMeasure()方法如下:
FrameLayout.onMeasure方法如下:(这个方法里面都很重要)
我们先看 , measureChildWithMargins 方法,
getChildMeasureSpec 方法内容如下:
那么假如我们写的布局根节点是LinearLayout,那么就会在执行到View.measure方法里面的onMeasure方法时,就会调用到LinearLayout.onMeasure方法,具体内容如下:
通过源码可以看到,还是会循环调用子View , 就这样循环递归的测量完最里面的一个view,这个过程中onMeasure方法可能会被多次执行。
还是从ViewRootImpl.performTraversals开始
这里跟measure 调用流程其实一样,DecorView和FrameLayout没有重写layout方法,所以调用的是View.layout方法,
由于当前对象是decorView,所以调用的是DecorView.onLayout方法:
FrameLayout.onLayout 方法如下:
继续查看 View.draw方法
在这个方法里面,所有重要的方法都在里面,onDraw、dispatchDraw 等等都在里面,我看了下这个方法里面都挺重要就没删减,也都能看得懂。
到此View的整个绘制流程就搞清楚了。
关于子view测量
1、不管父View是何模式,若子View有确切数值,则子View大小就是其本身大小,且mode是EXACTLY
2、若子View是match_parent,则模式与父View相同,且大小同父View(若父View是UNSPECIFIED,则子View大小为0)
3、若子View是wrap_content,则模式是AT_MOST,大小同父View,表示不可超过父View大小(若父View是UNSPECIFIED,则子View大小为0)
关于绘制流程
我们自定义的view,基本上只需要重写 onMeasure、onLayout、onDraw即可