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即可