2018年7月23日 星期一

【Android】尋找特定View在ScrollView中的位置並滾動到定位

ScrollView中必須要再包一個「ViewGroup」才有辦法再放入其他View。(它只能容納一個ChildView。)

所以「(特定View)在ScrollView中的位置」其實是「(特定View)在此ViewGroup中的位置」。

但一般尋找「View在螢幕中絕對座標」的辦法無法用在此處。

以縱軸座標的ScrollView來說,「位置」其實是指「這個View距離ViewGroup上方邊界的距離」。

所以要使用View中的功能:getTop(),來取得.......

但這個功能取得的是View跟最接近的ViewGroup的距離。也就是說如果ScrollView和View之間不只一層ViewGroup,而是有多層ViewGroup,(為了做出複雜的版型,)那就必須要用一個迴圈將它們的「getTop()」通通取出來作加總...

舉例.....

假設ScrollView和View之間有ViewGroup(0)、ViewGroup(1)、ViewGroup(2)、ViewGroup(3),最後才是View,....如果已經可以清楚知道ViewGroup的數目,那就好辦,但如果不知道...

要從View取ParentView,(這東西可以直接轉型成「View類別」,)然後再從ParentView取ParentView...直到取出來的ParentView是ScrollView為止。

每次的getTop記得都要累加起來,得到的數值才是畫面上、視覺上,這個View在ScrollView中的位置。

2018年7月20日 星期五

【Java】Instanceof 的效能

Interface可以讓「無直接繼承關係」的物件之間共享相同屬性,──簡單來說,介面本身就是種屬性。

判讀這種屬性用的就是「instanceof」這個指令。


舉例:「設置一個介面稱為『Wing』,然後在怪物A的子怪物類別群中找到一隻,假設類別為怪物A2B,然後讓它擴充『Wing』介面。」如此一來,在一系列怪物中就可以跳過在「怪物A」、甚至「怪物A的父類別」中新增參數「Wing」。──雖然不一定會發生,這樣做的好處是「設計上彈性非常高」。

但是相較於判讀介面,判讀物件類別名稱只要十分之一的效能。(而且判讀物件類別名稱所消耗的效能又是直接判讀參數的一到三倍。)但最終物件類別名稱並無法達到我剛才所說的效果。

把所有都擴充了Wing介面的類別都集合在一起判斷,施作上不合理!(但......實際上可以這樣做。)


將所有屬性都集中在一個父類別,然後用子類別來「變化/初始化」這些參數,這在講求效能的情況下還是比較實在。但怎麼設計參數........每多增加一個參數,類別的物件實體在記憶體中占用的量就會增加。

所以一般來說都是使用位元運算子,一個短整數等於8bit,也就等於八個boolean值,直接宣告一個短整數省記憶體?還是宣告八個boolean省記憶體?...以後再測試。

2018年7月17日 星期二

【Android Fragment】如何保留畫面上的操作選項

(因為是「Fragment」,所以這篇文章中的某些技巧與思考才會有存在的價值。)

簡單來說,一個Fragment如果被暫時從畫面上退到「Stack」中,當它從「Stack」中回到畫面上時,如何保留上次Fragment介面中的操作紀錄,例如輸入框輸入的資訊內容。

方法其實很簡單,Fragment內要有個「全域變數A」來承接onCreateView中第一次產生的View,當下次Fragment從Stack中回到畫面時,優先判斷順序就變成先判斷「全域變數A」是否為空值(不是直接進行LayoutInflater),如果不為空值就改讀取「全域變數A」做接下來的操作。

但是當再背景停留太久、整個Fragment的資料都被回收.....這種招數就不管用了。

話說回來,除非每次操作資料都即時進SQL,不然這種事情是無解的。(頂多確保Fragment能正常顯示而已。)

(真正的解答是乖乖使用Argument。)

2018年7月5日 星期四

【Android】Render截圖

為什麼要註明Render截圖?

因為目前Android官方推出的標準截圖方法必須建立在「有辦法取得影片檔案的Description」上。

但影片格式越來越多樣,即使檔名不變,但Description可能無法支援的情況會發生。

所以必須要直接從Render上取得「要撥出的影像畫質內容」。

關鍵在於取得Render內的GL10。(其實不是「Render內」,而是onRenderDraw/onDrawFrame這些函數中,會取得GL傳入的GL10。)

取得後,資料轉換的方法就很固定了。
void screenShot(GL10 gl) {
     int screenshotSize = mCurrentViewportWidth * mCurrentViewportHeight;
        ByteBuffer bb = ByteBuffer.allocateDirect(screenshotSize * 4);
        bb.order(ByteOrder.nativeOrder());
        gl.glReadPixels(0, 0, mCurrentViewportWidth, mCurrentViewportHeight, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, bb);
        int pixelsBuffer[] = new int[screenshotSize];
        bb.asIntBuffer().get(pixelsBuffer);
        bb = null;
        Bitmap bitmap = Bitmap.createBitmap(mCurrentViewportWidth, mCurrentViewportHeight, Bitmap.Config.RGB_565);
        bitmap.setPixels(pixelsBuffer, screenshotSize-mCurrentViewportWidth, -mCurrentViewportWidth, 0, 0, mCurrentViewportWidth, mCurrentViewportHeight);
        pixelsBuffer = null;

        short sBuffer[] = new short[screenshotSize];
        ShortBuffer sb = ShortBuffer.wrap(sBuffer);
        bitmap.copyPixelsToBuffer(sb);

        //Making created bitmap (from OpenGL points) compatible with Android bitmap
        for (int i = 0; i < screenshotSize; ++i) {                  
            short v = sBuffer[i];
            sBuffer[i] = (short) (((v&0x1f) << 11) | (v&0x7e0) | ((v&0xf800) >> 11));
        }
        sb.rewind();
        bitmap.copyPixelsFromBuffer(sb);
        
        
    }