2016年4月11日 星期一

[Android] 使用WebView讀取網頁時,表格無法完整顯示的簡易替代方案

一開始是想用WebView讀取特定網頁,讓使用者可以方便,不用離開app到browser開啟
但採用後發現WebView讀取該網頁是以完整顯示上半段文章為基準,下半段表格則超出頁面橫向範圍,用手勢也無法移動。

這現象跟網站本身的寫法和相容性有關,同時,WebView也只是最簡單基本讀取網頁用的元件,不然就不需要辛苦開發browser了。

在不能改動網站前後端的前提下,研究了許多方式都不能移動畫面,後來看Android下大多瀏覽器也無法正確瀏覽,iPhone下Safari跟Chrome則可以顯示(看來跟元件底層及API也有點關係@@)。忘記是哪款瀏覽器版本可以完整顯示表格,雖然背景不會同步拉寬,但至少可以完整顯示內容,且Android下也只找到這個方式可以正確顯示,就朝此方向追尋。

但找了幾個方法都無法改善,其他大部分的畫面問題應可以用頭兩行解掉:


   webView.getSettings().setLoadWithOverviewMode(true);
   webView.getSettings().setUseWideViewPort(true);
   webView.getSettings().setBuiltInZoomControls(true);


隔了好一陣子一度放棄,最後發現有人加了setInitialScale(1)這行,配合setLoadWithOverviewMode(true),setUseWideViewPort(true),
總算可以讓表格固定完整顯示。

   webView.setWebViewClient(new webClient());
   webView.setInitialScale(1);
   webView.getSettings().setJavaScriptEnabled(true);
   webView.getSettings().setLoadWithOverviewMode(true);
   webView.getSettings().setUseWideViewPort(true);
   webView.loadUrl(uri);

後記:
回頭拿Android Nexus 5x 6.0跟iPhone 6s 9.3.1比較,
Android下: Chrome v49.0, Opera v36.1, FireFox v45.0.1, Dolphin v11.5.5, Boat Browser v8.7.3,只有Dolphin做了表格完整顯示(Scale固定,背景維持框架原始大小),Chrome則是可以有技巧的左右滑一下但回不來...,其他都是表格無法完整瀏覽或移動。
iPhone下(沒看瀏覽器版本):Chrome, 
Safari,Opera,Dolphin各瀏覽器都是單純用手勢左右移動就可以瀏覽表格(背景維持框架原始大小)

2016年1月10日 星期日

[Android] GridView與GridLayout使用上的差異

GridView:
如果你手邊有一批圖像或data, 需要將他們放進格子狀的畫面呈現, 甚至在滑動頁面時需要刷新裡面的圖像/data, Ex:相簿的九宮格(thumbnails), 可以使用GridView. 它可以幫你做到重複使用及回收這些格位, 提升使用上的效能.
GridView是透過Adapter轉接器, 類似ListView的作法, 將手邊的資料們根據index, 指定至這些一格一格的位置. 當然, 你也可以定義一格裡面的內容, 同時包含圖像或文字, 做成一個複合的Item, 提供給Adapter來介接.

GridLayout:
適用於畫面的佈局配置, 類似LinearLayout. 可針對Android元件做不同比重分配,  Ex:計算機按鈕. 下方為google blog提出的兩個範例.

GridLayout範例

[Android] 新project出現android.support.v7.internal.app.WindowDecorActionBar錯誤

此時Android Studio會提示你修正重新Build project, 但路徑不對的話, 仍然會出現錯誤




解決方式style可以替換使用
(1) NoActionBar,
(2) 以Base.Theme.AppCompat.Light.DarkActionBar取代Theme.AppCompat.Light.DarkActionBar





原因是style內使用到Android 5.0 (SDK 21)以前的Android ActionBar style.

AppTheme繼承自Theme.AppCompat.Light.DarkActionBar style

AndroidManifest.xml於Application style使用AppTheme

而ActionBar於已經被ToolBar取代, 使用ToolBar通常styles樣式會設為NoActionBar, 並在需要放置的layout內定義ToolBar 元件

Android 5.0 style (v21)
NoActionBar
定義ToolBar元件

[Android] Fragment 及 v4 support Fragment差異

1. android.app.Fragment - 支援Android 3.0 (API 11)以上版本
2. android.support.v4.app.Fragment - 如需支援Android 3.0以前再使用


android.app.Fragment:
(1)使用FragmentManager操作Fragment時, 必需使用 getFragmentManager()取得android.app.FragmentManager

android.support.v4.app.Fragment:
(1)裝載的Activity必須extends FragmentActivity,
(2)使用FragmentManager操作Fragment時, 必需使用 getSupportFragmentManager()取得android.support.v4.FragmentManager


2014年2月25日 星期二

[Android] eclipse除錯

1. 刪除support library後, 使用library的project再次讀取卻error?

2. 刪除project, 再次從workspace import進來, eclipse顯示錯誤無法匯入?
"Invalid project description. overlaps the location of another project"
改用 General > Existing Projects Into Workspace 就行了
http://blog.changyy.org/2013/08/android-eclipse-import-invalid-project.html


3. →刪除project, 再次從workspace import進來, 勾選copy project into workspace, 檔案會覆蓋(MainActivity.java呈現空白)

4. R.檔消失, 重開eclipse或重新匯入專案都不會好
→ Clean再Build project會好, 如果沒出現通常是XML檔名有問題, 這次是target=android-16版本太低不能供theme-color使用

http://wangshifuola.blogspot.tw/2011/06/androidrjava.html
http://ephrain.pixnet.net/blog/post/47238762-%5Bandroid%5D-android-%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98%EF%BC%9A%E4%BF%AE%E5%BE%A9-r.java-%E4%B8%8D%E8%A6%8B%E7%9A%84%E5%95%8F
http://www.mybringback.com/travis-android-help/1/hello-world/

4. eclipse變數反白設定
http://blog.xuite.net/akuox/caffeine/43266804

5. The connection to adb is down, and a severe error has occured. 再重啟Eclipse沒好
Build Automatically忘了開, 裝置管理員關閉adb第一個, 再重啟Eclipse後OK

http://fecbob.pixnet.net/blog/post/36105987-android%E4%B8%ADthe-connection-to-adb-is-down%E8%A7%A3%E6%B1%BA%E6%96%B9%E6%B3%95

6. 打字覆蓋到後面的字
案到insert(INS)鍵, 再按一次會回來

7. 更新ADT 22.6顯示No Updates were found.
http://blog.mosil.biz/2013/02/this-android-sdk-requires-android-developer-toolkit-above-version/

2014年1月16日 星期四

[Android] Android Development Tutorial 6速記- parsing XML use DOM (1)

1. android:ems=“10”

android:ems = "10" 设置TextView或者Edittext的宽度为10个字符的宽度。当设置该属性后,控件显示的长度就为10个字符的长度,超出的部分将不显示。

2.
<EditText  
     android:id="@+id/phone"
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content">
     <requestFocus/>
</EditText>
get the focus, 滑鼠游標在的位置, 鍵盤自動跳出, 記得結尾要有>記號
當多個地方使用 requestFocus,只會有一個地方生效,就是最後執行 requestFocus 的地方
http://cw1057.blogspot.tw/2011/11/android-edittext-focus.html

EditText.requestFocus();//让EditText获得焦点,但是获得焦点并不会自动弹出键盘
http://blog.csdn.net/qq435757399/article/details/7947862

3. EditText設android:layout_weight="1", TextView不設,只有"wrap_content"
TextView 先佔用了"wrap_content"大小, 再讓EditText占用剩餘部分的1

weight是指某个组件在布局中【剩余空间】中的显示权重,那么所谓的剩余空间又是什么意思呢,其实是在没有设置weight属性的控件优先显示的情况,将未占用的布局空间合理分配给设置过weight的组件
<Button>     </>
<TextView> </>

5. Layout設Android 4.4(API 19)無法用colors寫字串直接在backgroud選取? →設Android4.3可以

6. dp & sp
px(pixel)是絕對大小, 在不同設備差異較大不建議使用
設定dp是依照設備pixel的密度分成四個係數, 係數相乘以該圖的dp就是pixel, 使每個設備差異不會太大, 最常用
sp(與縮放無關的抽象像素), 依設備用戶調整文字尺寸大小(小、正常、大、超大等等)時有所不同, 通常用在文字
http://rritw.com/a/caozuoxitong/Android/2012/1106/249015.html

7. 通过设置属性android:layout_span来声明一个widget跨越的列数
http://hi.baidu.com/hemisp/item/35e12acfd12285daef183bcf
android:layout_span="1"                     android:layout_span="2"


8. android:padding="5dp" →元件的上下領域大小(兩水平線的距離), 這邊用在TableLayout, ScrollView跟TextView, 也可以在layout控制面版上改

9. android:stretchColumns="yes" 元件延展到整個剩餘可用的範圍, 這邊用在TableLayout

10. android:background="@android:color/transparent" →透明效果

11. android:textIsSelectable="true"

Android SDK 3.0 版本之後所支援的文字選取 (textIsSelectable) 之新功能,以允許使用者在執行階段可選取並複製該TextView 文字標籤介面元件所顯示的資料。



2014年1月13日 星期一

[Android] Android Development Tutorial 7速記- parsing XML use DOM (2)

1. 資料儲存的方式之一
Shared Preferences





Store private primitive data in key-value pairs.
使用 Context.getSharedPreference(String name, int mode) 方法可以建立多個 SharedPreferences 檔案,每一個檔案透過 name 參數來命名,該檔案的讀寫權限則是利用 mode 參數來做設定。
Your data storage options are the following:
Shared Preferences
Store private primitive data in key-value pairs.
Internal Storage
Store private data on the device memory.
External Storage
Store public data on the shared external storage.
SQLite Databases
Store structured data in a private database.
Network Connection
Store data on the web with your own network server.




2. 鍵值對 key-value pairs, 用一個屬性對應一個值的方式 通过键key便可以找到相应的值 , 只有找到其他語言的解說如下列網址:




3.
// Table inside the scroll view that holds stock symbols
// and buttons
private TableLayout stockTableScrollView;
為什麼這裡宣告的是TableLayout, 而不適TableRow或ScrollView?


4.
// Get the saved stocks
String[] stocks = stockSymbolsEntered.getAll().keySet().toArray(new String[0]);
getSharedPreferences.getAll()後為什麼能呼叫.keySet()和.toArray? 

keySet() is a method that returns a set of all the keys of the Map(public Set<K> keySet ()). So, methods are not to be imported. Though Map is not imported but the return type of getAll()method is Map<String, ?> so it can be directly accessed



跟Hash Map相關, 暫時回去看java.util.Map<K, V>
→ Map介面的實作可用來建立鍵值對應資料(補充比喻: 像搜尋關鍵字可找到對應的資料for第二點疑惑)
Set介面實做Collection介面, 
Collection介面為收集物件用, Set介面為收集過程中, 不重複收集相同物件用

SharedPreferences.getAll()   public abstract Map<String, ?> getAll ()
Map.keySet()                      public abstract Set<K> keySet () →抽象方法,Set<K>型態
Set.toArray()                       
public abstract T[] toArray (T[] array)


Thanks for your help, I think I understand. Because you are returning a map reference through getAll() and then calling keySet() on that you can then use the keySet() with out having to import the Map class, unlike the situation you pointed out where returning getAll() directly to a defined map object would require the import of the Map class.
因為經由getAll()回傳一個Map參考後直接呼叫keySet()來使用(keySet是Map介面底下的方法),不是將getAll()回傳到一個Map定義的物件, 所以不用import Map底下實作的類別

→同理keySet()回傳Set參考後呼叫toArray()直接使用, , 所以不用import Set底下實作的類別

  1. allUserName = sp.getAll().keySet().toArray(new String[0]);  
  2.                 // sp.getAll()返回一张hash map  
  3.                 // keySet()得到的是a set of the keys.  
  4.                 // hash map是由key-value组成的  


5. (延伸至4) Set<K>的意思?
<>指的是泛型

? 表示不确定的java类型。 
T  表示java类型。 
K V 分别代表java键值中的Key Value。 
E 代表Element。 

<T>是 Type
<K,V>是说键值对~就是 Key 和 Value HashMap
<E> 是 Element
<?> 是 通配符

6. 
// Sort the stocks in alphabetical order
Arrays.sort(stocks, String.CASE_INSENSITIVE_ORDER);
sort方法的使用?
sort()為Array陣列的方法, collections也有sort()方法
http://openhome.cc/Gossip/JavaGossip-V1/ArraysClass.htm
Java技術手冊 9-23頁


对集合框架进行排序
如果已经理解了Arrays.sort()对数组进行排序的话,集合框架的使用也是大同小异。只是将Arrays替换成了Collections,注意Collections是一个类而Collection是一个接口.
http://hi.baidu.com/yljf184/item/5d7f8c2c36b9960b42634aca


sort(char[] array)
Sorts the specified array in ascending numerical order.
sort(T[] array, Comparator<? super T> comparator)
Sorts the specified array using the specified Comparator.
sort(Object[] array)
Sorts the specified array in ascending natural order.
sort(T[] array, int start, int end, Comparator<? super T> comparator)
Sorts the specified range in the array using the specified Comparator.
sort(Object[] array, int start, int end)
Sorts the specified range in the array in ascending natural order.
是哪一個API方法?
sorts()對物件排序有兩個版本, 一個是你收集在陣列中的物件必須是Comparable(否則會拋出ClassCastException), 另一個版本則可以傳入Comparator指定排序方式。
Java技術手冊 9-23頁

猜測是Comparable方式(但不知哪個?), 因為String類別有實作Comparable介面
→eclipse顯示為這個:
sort(T[] array, Comparator<? super T> comparator)
Sorts the specified array using the specified Comparator.


7. 二元搜尋要先排序
http://blog.ccc99.tw/2010/05/arraysbinarysearch.html

嚴格按字母表順序排序,也就是忽略大小寫排序 Case-insensitive sort
  Arrays.sort(strArray, String.CASE_INSENSITIVE_ORDER);
http://www.javaworld.com.tw/jute/post/view?bid=29&id=308357

8.  if(newStockSymbol!=null) 
這裡newStockSymbol怎麼知道是輸入的值?


9.
insertStockInScrollView(newStockSymbol, Arrays.binarySearch(stocks, newStockSymbol));
→將stock插入到ScrollView(要插入的值是newStockSymbol, 順序用二元搜尋找出(陣列名, 要插入的值))

陣列中二元搜尋法?
在以排序的陣列中, 將欲搜尋的值跟中間值做比對, 比較後, 中間值以外的另一邊即可忽略不比較, 循著這個規則一值拆半, 是個用以節省時間的方法
http://program-lover.blogspot.tw/2008/08/binary-search.html

insertStockInScrollView(stocks[i], i);
                     →(值, 順序)

10. private void saveStockSymbol(String newStock){
這方法哪時呼叫?
→按下EnterButton時呼叫並傳入引數

11. SharedPreferences.Editor
→修改SharedPreferences物件的介面

Android的共享選項編輯器(SharedPreferences.Editor)

共享選項編輯器(SharedPreferences.Editor)是一個用於修改SharedPreferences對象值的接口. 編輯選項值後, 調用commit()或apply()方法以更新SharedPreferences.
http://androidbiancheng.blogspot.tw/2011/02/androidsharedpreferenceseditor.html

可透過SharedPreferences.Editor編輯介面來更新偏好設定內容。這項作業必須先使用edit()方法取得SharedPreferences.Editor編輯介面,再使用putBoolean()putFloat()putInt()putLong()putString()方法來分別寫入布林資料、浮點數資料、整數資料、長整數資料及字串資料到偏好設定檔中。 public abstract SharedPreferences.Editor putBoolean (String key, boolean value)
    public abstract SharedPreferences.Editor putFloat (String key, float value)     public abstract SharedPreferences.Editor putInt (String key, int value)     public abstract SharedPreferences.Editor putLong (String key, long value)     public abstract SharedPreferences.Editor putString (String key, String value) 在此key表示偏好設定檔中的資料名稱,value則是資料值。有一點要注意,這些偏好設定值並不會立即更新,而是等到執行commit()方法後才會寫回偏好設定檔。 →或apply()
http://nkeegamedev.blogspot.tw/2010/08/android-sharedpreference.html

12. stockSymbolsEntered.edit()
提供一editor給SharedPreferences物件, 經由它可以用來修改資料

13. if(isTheStockNew == null)
為什麼這裡是空值?

14. LayoutInflater的作用?
加載自定義布局文件
不同点是LayoutInflater是用来找layout下xml布局文件,并且实例化!而findViewById()是找具体xml下的具体 widget控件(如:Button,TextView等)。
像這裡的TableLayout中ScrollView, 先用LayoutInflater抓進來, 並且把其中的元件初始化









15. 方法的命名與參數傳遞到底怎實作?
有回傳值時 :
因為回傳值是暫存於記憶體, 因此一定要在方法名稱前宣告回傳值的資料型別, 才知道要配置多大的記憶空間
當方法加上 "static" 修飾詞時稱為靜態方法, 這種方法屬於類別方法, 而非實體方法, 可以在類別外面直接以類別名稱呼叫, 不須事先建立物件實體.

參數與引數有何不同 ?
參數 (Parameter) 與引數 (Argument) 概念不同, 參數是方法宣告中欲傳入之變數, 而引數則是呼叫該方法時, 實際傳入的資料. 其實兩者是互相對應的.

從 static 的 main 方法中呼叫 add, 這個類別內方法 add 也必須宣告成 static, 否則該方法是無法被參考到的 :
"Javatest.java:3: non-static method add(int,int) cannot be referenced from a static context"

呼叫靜態方法 :
靜態方法為宣告時添加 "static" 修飾詞者, 係類別方法, 在類別外可以直接以類別名稱呼叫, 不須建立物件實體.
方法所屬類別名稱.方法名稱(引數);
例如 :
public class Javatest {
  public static void main(String[] args) {
    int sum=Dosomething.add(12,21);
    System.out.println("Sum=" + sum);
    }
  }
class Dosomething {
  public static int add(int a, int b) {
    return a+b;
    }
  }

呼叫非靜態方法 :
非靜態方法屬於物件實體方法, 必須先建立物件實體之後, 透過物件參考來呼叫 :
方法所屬類別名稱 物件參考變數名稱=new 方法所屬類別名稱();
物件參考變數名稱.方法名稱();
例如 :
public class Javatest {
  public static void main(String[] args) {
    Dosomething ds=new Dosomething();
    int sum=ds.add(12,21);
    System.out.println("Sum=" + sum);
    }
  }
class Dosomething {
  public int add(int a, int b) {
  return a+b;
  }
}
http://tony1966.myweb.hinet.net/java/core/method_parameter.htm

16. 這裡為什麼是傳給stockSymbolTextView?
TextView newStockTextView = (TextView) newStockRow.findViewById(R.id.stockSymbolTextView);

newStockTextView.setText(stock);

17. if(stockSymbolEditText.getText().length() < 0){
這邊可以這樣判斷字串大於0, 學起來用

18. 無焦點時阻止輸入法彈出
InputMethodManager imm = (InputMethodManager) getSystemService (Context.INPUT_METHOD_SERVICE);

imm.hideSoftInputFromWindow(stockSymbolEditText.getWindowToken(), 0);

InputMethodManagerhttp://my.oschina.net/jbcao/blog/61035
WindowManager
INPUT_METHOD_SERVICE
http://developer.android.com/reference/android/view/WindowManager.html

有焦點時:
http://4225953-163-com.iteye.com/blog/1235324

19. v.parent抓buttom上一層的TableRow

20. ACTION_VIEW 显示数据给用户
常见的Activity Action Intent常量
常量名称
常量值
意义
ACTION_MAIN
android.intent.action.MAIN
应用程序入口
ACTION_VIEW
android.intent.action.VIEW
显示数据给用户
http://hualang.iteye.com/blog/983471

Intent 用法大公開, 這邊有可用的例子

uri.parse
→加網址
一般找到的用法, uri分兩次寫: 
  1. /*查找某个地方并作出标注*/  
  2. Intent intent=new Intent(Intent.ACTION_VIEW);  
  3. String url = "https://maps.google.com/maps?q=31.207149,121.593086(金科路)&z=17&hl=en";  
  4. Uri uri = Uri.parse(url);  
  5. intent.setData(uri);  
  6. startActivity(intent);