2015年12月24日 星期四

Android 實戰記錄 (18) - PopupWindow 點擊以外消取問題,Back鍵問題

遇到某些手機,點擊以外範圍無效的狀況,
及Back鍵要如何也有取消的功能

花了不少時間找,應該以下這個連結能夠解決問題
http://blog.csdn.net/woshicaixianfeng/article/details/7075066

及量測 measure 時,會有平版發生Exception

只好把我改過的PopupWindow改成如下

LayoutInflater layoutInflater =(LayoutInflater)getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);
View popupView = layoutInflater.inflate(R.layout.popup_setting, null);
popupWindow = new PopupWindow(popupView,ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
RelativeLayout lay_popwin = (RelativeLayout) popupView.findViewById(R.id.lay_popwin);
lay_popwin.setOnKeyListener(new View.OnKeyListener() {
   public boolean onKey(View v, int keyCode, KeyEvent event) {
      if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_BACK)
         popupWindow.dismiss();
      return false;
   }
});

int xOffset = 0;
try {
   popupView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
   xOffset = -(popupView.getMeasuredWidth() - popupView.getWidth());
}catch (Exception ex) {
   DisplayMetrics displayMetrics = new DisplayMetrics();
   this.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
   //平版measure出錯,直接處理xOffset   //依比例調整xOffset   int dp = 150;//popupWindow 為 150 dp   xOffset = -(int)(dp*displayMetrics.scaledDensity);
   ex.printStackTrace();
}

//解決點外無法取消Popup Window問題popupWindow.setBackgroundDrawable(new BitmapDrawable());
// 使其聚集popupWindow.setFocusable(true);
// 设置允许在外点击消失popupWindow.setOutsideTouchable(true);
//刷新状态(必须刷新否则无效)popupWindow.update();
popupWindow.showAsDropDown(btn_setting, xOffset + 70, -10);


2015年12月23日 星期三

Android 實戰記錄 (17) - 取得螢幕大小、dp、變更Layout 高度

FrameLayout layout = (FrameLayout) findViewById(R.id.layout);
ViewGroup.LayoutParams lp =layout.getLayoutParams();

DisplayMetrics displayMetrics = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);

String px = displayMetrics.widthPixels + " x " + displayMetrics.heightPixels;
String dp = displayMetrics.xdpi + " x " + displayMetrics.ydpi;
String density = "densityDpi = " + displayMetrics.densityDpi + ", density=" + displayMetrics.density + ", scaledDensity = " + displayMetrics.scaledDensity;
Log.e("test", "px = " + px + ", dp = " + dp + ",density " + density);
Log.e("test", "framelayout height = " + lp.height);
Log.e("test", "framelayout width = " + lp.width);

lp.height = displayMetrics.widthPixels/3;

參考網址:
http://saminjava.blogspot.tw/2013/09/android.html

http://ikevin.tw/?cat=9

2015年12月21日 星期一

Android 實戰記錄 (16) - ViewPager not use Fragment

這次很特別,
剛好要使用ViewPager,但跟以往不同,
因為使用的是Api 8且使用的是Android Studio
導致
因為API 8 無法使用Fragment ,Fragment只支援API 11 以上。
接著viewpagerindicator 用Gradle,我又嫌麻煩。

就得自己寫ViewPager、自己動態產生頁面、自己實作viewpagerindicator

參考這個人寫的程式,大部分就可以完成
http://huli.logdown.com/posts/283657-android-viewpager-page

只是他或許少給了什麼(style)
所以我幫他補齊這一點。

而且我不能讓他按radio button

<!--ViewPager Radio Button --><style name="viewpagerindicator_circle">
    <item name="android:layout_width">11dp</item>
    <item name="android:layout_height">11dp</item>
    <item name="android:button">@drawable/view_pager_circle_background</item>
    <item name="android:editable">false</item>
    <item name="android:layout_marginLeft">2dp</item>
    <item name="android:layout_marginRight">2dp</item>
</style>

然後也很不幸的,我的circle,有大有小,有透明。

所以實作了一個圈圈,是雙圓圈。

<?xml version="1.0" encoding="utf-8"?><layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Larger blue circle in back -->    <item>
        <shape android:shape="oval">
            <solid android:color="#0fff"/>
            <size                android:width="9.5dp"                android:height="9.5dp"/>
        </shape>
    </item>
    <!-- Smaller red circle in front -->    <item>
        <shape android:shape="oval">
            <!-- transparent stroke = larger_circle_size - smaller_circle_size -->            <stroke android:color="@android:color/transparent"                android:width="5dp"/>
            <solid android:color="#cfff"/>
            <size                android:width="7.5dp"                android:height="7.5dp"/>
        </shape>
    </item>
</layer-list>

接著因為對方是固定的,不是動態產生
我就實作動態產生RadioButton

動態產生,又會導致layout跑版,只好態動設定寬高、邊距

/** * 取得Radio Button Circle Indicator * @return */public RadioButton getRadioButtons() {
   float radio_dps = 9.5f;
   float margin_dps = 2f;
   final float scale = getResources().getDisplayMetrics().density;
   int radioSize = (int) (radio_dps * scale + 0.5f);
   int margin = (int) (margin_dps * scale + 0.5f);
   RadioButton radio = (RadioButton)getLayoutInflater().inflate(R.layout.item_view_pager_circle, null);
   radio.setHeight(radioSize);
   radio.setWidth(radioSize);
   radio.setButtonDrawable(R.drawable.view_pager_circle_background);

   LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1); // , 1是可選寫的   lp.setMargins(margin, 0, margin, 0);
   lp.gravity = Gravity.CENTER;
   radio.setLayoutParams(lp);
   radio.setEnabled(false);

   return radio;
}


radioGroup.addView(getRadioButtons());


RadioButton radio = (RadioButton) radioGroup.getChildAt(0);
radio.setChecked(true);

按下圖,又要能夠跳到某一頁面。

我在ImageView賽了Tag,是該筆資料的物件。

在加上輪播

// 启动banner自动轮播public void bannerStartPlay() {
   if (mBannerTimer != null) {
      if (mBannerTimerTask != null)
         mBannerTimerTask.cancel();
      mBannerTimerTask = new BannerTimerTask();
      mBannerTimer.schedule(mBannerTimerTask, 5000, 5000);// 5秒后执行,每隔5秒执行一次   }
}

// 暂停banner自动轮播public void bannerStopPlay() {
   if (mBannerTimerTask != null)
      mBannerTimerTask.cancel();
}

class BannerTimerTask extends TimerTask {
   @Override   public void run() {
      Message msg = new Message();

      if (pagerAdapter.getCount() <= 1)
         return;
      int currentIndex = viewPager.getCurrentItem();
      if (currentIndex == pagerAdapter.getCount() - 1)
         msg.what = 0;
      else         msg.what = currentIndex + 1;

      mTimerHandler.sendMessage(msg);
   }
}

mBannerTimer = new Timer();
mTimerHandler = new Handler() {
   public void handleMessage(Message msg) {
      viewPager.setCurrentItem(msg.what);
      super.handleMessage(msg);
   }
};

大至上就完成了。

很累的過程。


2015年12月18日 星期五

Android 實戰記錄 (15) - GridView 格線

根據
http://dyingbleed.iteye.com/blog/1232723
http://stackoverflow.com/questions/18309422/how-to-give-single-line-border-to-gridview-android

只要將以下寫完後
GridView gv = findViewById(R.id.my_grid_view);
gv.setBackgroundColor(Color.WHITE);
gv.setVerticalSpacing(1);
gv.setHorizontalSpacing(1);
及item也設背景,就可以完成格線。

但測試後,似乎上邊界與下邊界無格線。
所以需再自行增加View做處理
<View    android:layout_width="match_parent"    android:layout_height="1dp"    android:background="@color/white"/>

Android 實戰記錄 (14) - 反編譯

因為遇到有人寄簡訊冒用官方請求對方下載apk,
但這apk非官方釋出的,其中會盜取簡訊資訊,
導致如一些重要資訊會傳至對方的Server上

所以去下載該問題apk進行反編譯,瞭解他的內容為何
可參考
http://magiclen.org/android-decompiler/

由這個連結,可以取得apk 轉為 jar
https://bitbucket.org/pxb1988/dex2jar/downloads

再取得jd-gui 進行jar 解析,反編譯,就可以觀看程式碼內容,進行分析
https://code.google.com/p/innlab/downloads/detail?name=jd-gui-0.3.3.windows.zip&


2015年12月17日 星期四

Android 實戰記錄 (13) - Android 6.0 權限問題

今天為了處理簡訊讀取問題
開一個新的專案來處理測試

我的手機是Android 6.0
開發專案是targetSdkVersion是23
意外就剛好遇到6.0之後的權限問題

根據以下專業的文章說明
http://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en

取得以下資訊
 In Android 6.0 Marshmallow, application will not be granted any permission at installation time. Instead, application has to ask user for a permission one-by-one at runtime.

Anyway this new Runtime Permission will work like described only when we set the application'stargetSdkVersion to 23 which mean it is declared that application has already been tested on API Level 23. And this feature will work only on Android 6.0 Marshmallow. The same app will run with same old behavior on pre-Marshmallow device.

很不湊巧如果使用的是targetSdkVersion 23的話,

過去的權限方式,將會出問題。

加AndroidMainfest.xml不一定能解決問題。

因為我剛好使用的是開發模式,直接Builder進手機,
然後就直接出問題。
可能沒有直接授權的關係。

需要到「設定」→「應用程式」→權限,變更權限後,

這種問題就能夠被解決。(在開發方面的問題)
就不會在開發時,一直卡關在「java.lang.SecurityException」這個問題上

Android 實戰記錄 (12) - 可擴展GridView

因為需要GridView 自的產生項目,但又不使用他的Scroll,想依他的項目自動增長height
需要設定layout_height=wrap_content

以下這個方式可以解決問題
http://stackoverflow.com/questions/8481844/gridview-height-gets-cut

package com.example;
public class ExpandableHeightGridView extends GridView
{

    boolean expanded = false;

    public ExpandableHeightGridView(Context context)
    {
        super(context);
    }

    public ExpandableHeightGridView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public ExpandableHeightGridView(Context context, AttributeSet attrs,
            int defStyle)
    {
        super(context, attrs, defStyle);
    }

    public boolean isExpanded()
    {
        return expanded;
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        // HACK! TAKE THAT ANDROID!
        if (isExpanded())
        {
            // Calculate entire height by providing a very large height hint.
            // View.MEASURED_SIZE_MASK represents the largest height possible.
            int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
                    MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, expandSpec);

            ViewGroup.LayoutParams params = getLayoutParams();
            params.height = getMeasuredHeight();
        }
        else
        {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    public void setExpanded(boolean expanded)
    {
        this.expanded = expanded;
    }
}
<com.example.ExpandableHeightGridView
    android:id="@+id/myId"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:horizontalSpacing="2dp"
    android:isScrollContainer="false"
    android:numColumns="4"
    android:stretchMode="columnWidth"
    android:verticalSpacing="20dp" />
最開始的時候要設定

mAppsGrid = (ExpandableHeightGridView) findViewById(R.id.myId);
mAppsGrid.setExpanded(true);

但如果資料過多,可能ScrollView會移到最下面。
所以需在OnCreate加上

scrollView = (ScrollView) findViewById(R.id.scrollView);
scrollView.smoothScrollTo(0, 0);