ラベル android の投稿を表示しています。 すべての投稿を表示
ラベル android の投稿を表示しています。 すべての投稿を表示

2014年12月4日木曜日

単一Fragmentを表示するActivityの共通化

全画面想定のFragmentをActivityで取り回したい場合。AaaFragment, BbbFragmentに合わせてAaaActivity, BbbActivityとか作るのは面倒なのでActivityのWrapperを共通化。

Fragmentは public static XxxFragment newInstance(Bundle args);を実装している想定。
画面遷移時は、FragmentからならWrapperActivity.openFragmentActivity(getActivity(), SecondFragment.class, secondFragmentsArguments); という感じで行える。

package hoge.fuga.activities;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.View;
import android.view.View.OnClickListener;
import jp.arithmetic.arithmusic.R;
import jp.arithmetic.arithmusic.model.FragmentReplacer;

public class WrapperActivity extends Activity {
 public static final String TAG = "WrapperActivity";
 public static final String ARGS_FRAGMENT = "app-fragment";
 
 
 /** 
  * 1つのFragmentを全面に表示する共通化Activity
  * @param fromActivity
  * @param clazz
  * @param args
  */
 public static void openFragmentActivity(Activity fromActivity, Class clazz, Bundle args) {
  // setup bundle
  if (args == null) {
   args = new Bundle();
  }
  args.putString(ARGS_FRAGMENT, clazz.getName());
  
  // setup intent
  Intent i = new Intent(fromActivity, WrapperActivity.class);
  i.putExtras(args);
  
  // start activity
  fromActivity.startActivity(i);
 }
 
 /** 
  * close
  * @param fromActivity
  */
 public static void closeFragmentActivity(Activity fromActivity) {
  fromActivity.finish();
 }
 
 public static void closeToStartActivity(Activity fromActivity) {
  Intent i = new Intent(fromActivity, SomeStartActivity.class);
  i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
  fromActivity.startActivity(i);
 }
 
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_empty_container);

  // intentパラメータ優先
  Bundle args = (getIntent() != null) ? getIntent().getExtras() : savedInstanceState;
  if (args == null) {
   throw new RuntimeException("Wrapper: Empty arguments");
  }
  
  // 呼び出しFragment特定、初期化
  String className = args.getString(ARGS_FRAGMENT);
  if (className == null || className.isEmpty()) {
   throw new RuntimeException("Wrapper: Empty class name");
  }
  Fragment f = null;
  try {
   Class clazz = Class.forName(className);
   Method newInstance = clazz.getMethod("newInstance", Bundle.class);
   f = (Fragment)newInstance.invoke(null, args);

   replaceFragment(f);
   
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
   finish();
  } catch (NoSuchMethodException e) {
   e.printStackTrace();
   finish();
  } catch (IllegalAccessException e) {
   e.printStackTrace();
   finish();
  } catch (IllegalArgumentException e) {
   e.printStackTrace();
   finish();
  } catch (InvocationTargetException e) {
   e.printStackTrace();
   finish();
  }
 }
 
 @Override
 public void onBackPressed() {
  if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
   closeFragmentActivity(this);
  } else {
   super.onBackPressed();
  }
 }
 
 
 public void replaceFragment(Fragment f) {
  getSupportFragmentManager()
  .beginTransaction()
  .addToBackStack(null)
  .replace(R.id.empty_container, f)
  .commit();
 }
}

2014年11月17日月曜日

AndroidでBlur effect

要はiOS7以降のBlur effectぽいことをしたい場合。
android-stackblurを使う。
・RenderScriptはradiusがMAX25までしか設定できないぽいので期待しない。
・Eclipse想定


StackBlurライブラリの開発プロジェクトへのインストール

NDK導入
・stackblurをDLして、StackBlurディレクトリをプロジェクトimport。
・プロジェクトのコンテキストメニューから、Build Project
・libsディレクトリ配下にビルド成果物ができるので、まるっと開発プロジェクトのlibs配下にコピー
※stackblurのrenderscript8.jarでの競合が無ければIs Libraryでの追加でも大丈夫かも。


利用例

StackBlurManager _stackBlurManager = new StackBlurManager(orig);
_stackBlurManager.processNatively(radius);
Bitmap blurred = _stackBlurManager.returnBlurredImage();

利用例:Dialogで使う場合

Dialogに背景画像設定する場合は、DialogのWindow層に設定。
>そうするとDialogの位置とサイズが崩れる。styleで色々設定しても駄目。
>なのでAlertDialogは諦めて自前でCustomViewを作る必要がある。
>それも含めたベースのDialogFragment

/hoge/fuga/AbstractDialogFragment.java
package hoge.fuga;

import com.enrique.stackblur.StackBlurManager;

import hoge.fuga.R;

import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnShowListener;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.FrameLayout;

abstract public class AbstractDialogFragment extends DialogFragment implements OnShowListener {

    public static final String TAG = "AbstractDialogFragment";

    protected Dialog mDialog;
    private ViewGroup mContainer;


    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        mDialog = super.onCreateDialog(savedInstanceState);

        // Get status bar height
        Rect rectgle= new Rect();
        getActivity().getWindow().getDecorView().getWindowVisibleDisplayFrame(rectgle);
        int statusBarHeight = rectgle.top;

        // Screen shot http://stackoverflow.com/a/9596132/1121509
        View v = getActivity().getWindow().getDecorView();
        v.setDrawingCacheEnabled(true);
        Bitmap ss = v.getDrawingCache();
        if (ss != null) {
            ss = Bitmap.createBitmap(ss, 0, statusBarHeight, ss.getWidth(), ss.getHeight() - statusBarHeight);
        }
        v.setDrawingCacheEnabled(false);

        // Blur effect
        if (ss != null) {
            int radius = (int) (ss.getHeight() * 0.25);
            radius = radius > 100 ? 100 : radius;
            
            StackBlurManager _stackBlurManager = new StackBlurManager(ss);
            _stackBlurManager.processNatively(radius);
            Bitmap blurred = _stackBlurManager.returnBlurredImage();
            mDialog.getWindow().setBackgroundDrawable(new BitmapDrawable(getResources(), blurred));
        }

        // without title
        mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);

        // set listener
        mDialog.setOnShowListener(this);

        return mDialog;
    }
    
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // コンテナの設定
        mContainer = (ViewGroup) inflater.inflate(R.layout.dialog_base, container, false);
        return mContainer;
    }

    public void addViewToContainer(View contentView) {
        ((ViewGroup) mContainer.findViewById(R.id.dialog_container)).addView(contentView, 0);
    }

    @SuppressLint("NewApi")
    @SuppressWarnings("deprecation")
    @Override
    public void onShow(DialogInterface dialog) {
        // サイズ調整、このタイミングでないとうまく動かない
        Point size = new Point();
        Display display = getActivity().getWindowManager().getDefaultDisplay();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
            display.getSize(size);
        } else {
            size.x = display.getWidth();
            size.y = display.getHeight();
        }

        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams)mContainer.getLayoutParams();
        lp.width = size.x;
        lp.height = size.y;

        ViewGroup dialogContainer = (ViewGroup) mContainer.findViewById(R.id.dialog_container);
        FrameLayout.LayoutParams lp2 = (FrameLayout.LayoutParams) dialogContainer.getLayoutParams();
        lp2.topMargin = (size.y - dialogContainer.getMeasuredHeight()) / 2;
    }
}

/res/layout/dialog_base.xml



    
        
    


・Dialogを使う場合はAbstractDialogFragmentをextend。
・dialogの設定をするときはonCreateDialog()をoverrideしてsuper.onCreateDialog()してから設定。
・ViewはonCreateView()をoverrideして、super.onCreateView()してから子Viewを作り、super.addViewToContainer(childDialogView)する。


GPUImage for androidがblur effect対応してくれたら嬉しいな〜。

2014年6月28日土曜日

Androidでpinch in/outのjsイベント(gesturestart, gesturechange, gestureend)

gesturestart, gesturechange, gestureendはAndroidに無いので、独自実装。

var funcGestureStart = function (e) {};
var funcGestureChange = function (e) {};
var funcGestureEnd = function (e) {};

// iOS向けイベント設定
document.body.addEventListener('gesturestart', funcGestureStart, false);
document.body.addEventListener('gesturechange', funcGestureChange, false);
document.body.addEventListener('gestureend', funcGestureChange, false);

// Android向けイベント設定
var pinchDistance = 0;
document.body.addEventListener('touchstart',function(e){
    if(e.touches.length > 1){
        pinchDistance = Math.sqrt(Math.pow((e.touches[1].pageX - e.touches[0].pageX),2)+Math.pow((e.touches[1].pageY - e.touches[0].pageY),2));
        funcGestureStart(e);
    } else {
        pinchDistance = 0;
    }
},false);
document.body.addEventListener('touchmove', function (e) {
    if (pinchDistance <= 0) {
        return;
    }
    var newDistance = Math.sqrt(Math.pow((e.touches[1].pageX - e.touches[0].pageX),2)+Math.pow((e.touches[1].pageY - e.touches[0].pageY),2));
    var event = {scale: newDistance / pinchDistance};
    funcGestureChange(event);
});
document.body.addEventListener('touchmove', function (e) {
    if (pinchDistance <= 0) {
        return;
    }
    funcGestureEnd(e);
});