画像のリアルサイズモード、フィットサイズモード切り替え。完成ではない。アクションが決まらない。表示だけができた。
デバイスがポートレート表示(縦長)で画像がランドスケープ表示(横長)だとフィットモードは小さく表示されてしまうので90度回転させる事にした。そこでデバイスを横倒しにしたらどうなるのかエミュレーターで回転。回転直後は画像が乱れてしまったが、画像を進める、戻すでフィット表示になる。
自動で回転したときにコールバックされるメソッドを追加とオーバーライドする。表示手順は問題なさそうなので、現在の画像をイメージビューに再登録する。
余談、ImegeView の scaleTypeはレイアウトの組み合わせ、設定方法の間違い、何かしら問題があるのだろう。できるだけ楽をしたいのだが、まぁ仕方ない。苦労も思考の多様性を生むので良しとしなければ・・。でも、あぁ、楽がしたい。
新しい部分だけ注釈挿入。
【 FullscreenActivity.java 】
public class FullscreenActivity extends AppCompatActivity {
private final int DISPLAY_WIDTH = 0; // システム上アクティビティーの再起動が起こる
private final int DISPLAY_HEIGHT = 1; // 必要な時に呼び出す為に必要
private final ArrayList<MyNumbersInString> mFileNameList = new ArrayList<>();
private AssetManager mAssetManager;
private int targetIndexNo;
private boolean viewFlag, realSizeFlag, pageModeFlag;
private MyScrollView mMSV1, mMSV2;
private ImageView imageView1, imageView2;
private LinearLayout mL_Layout1, mL_Layout2;
private ViewSwitcher mViewSwitcher;
private GestureDetectorCompat mDetector;
private final MyGestureListener mGestureListener = new MyGestureListener();
// ******************************************************************
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen);
// 中略 //
mMSV1 = (MyScrollView) getLayoutInflater().inflate(R.layout.image1, null);
mMSV2 = (MyScrollView) getLayoutInflater().inflate(R.layout.image2, null);
mViewSwitcher = (ViewSwitcher) findViewById( R.id.viewSwither );
mViewSwitcher.addView( mMSV1, 0 );
mViewSwitcher.addView( mMSV2, 1 );
mViewSwitcher.setInAnimation(AnimationUtils.loadAnimation( this, android.R.anim.fade_in));
mViewSwitcher.setOutAnimation(AnimationUtils.loadAnimation( this, android.R.anim.fade_out));
pageModeFlag = true; // true(1page) false(2page)
realSizeFlag = false; // true(real mode) false(fit mode)
viewFlag = true; // true(sw0) false(sw1)
targetIndexNo = 0;
mAssetManager = getResources().getAssets();
setFileNameList();
imageView1 = findViewById(R.id.image_view1); // sw0
imageView2 = findViewById(R.id.image_view2); // sw1
setImage( imageView1, "image/" + mFileNameList.get(targetIndexNo).getName() );
setImage( imageView2, "image/" + mFileNameList.get(targetIndexNo).getName() );
mViewSwitcher.setOnTouchListener( MyTouchEventListener );
mDetector = new GestureDetectorCompat(this, mGestureListener );
mDetector.setOnDoubleTapListener( mGestureListener );
}
@Override
public boolean dispatchTouchEvent( MotionEvent event ) {
super.dispatchTouchEvent(event);
mDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
private final View.OnTouchListener MyTouchEventListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
};
private boolean doubleTapFlag = false;
class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
if( !doubleTapFlag ) {
if ( (int) e.getRawX() > ( getScreenSize(DISPLAY_WIDTH) / 2 ) ) { // デバイスサイズ呼び出し
if ( ++targetIndexNo >= mFileNameList.size() ) {
targetIndexNo = 0;
}
if ( viewFlag ) { // image1が表示されているので image2にセット
setImage( imageView2, "image/" + mFileNameList.get(targetIndexNo).getName() );
viewFlag = false;
} else {
setImage( imageView1, "image/" + mFileNameList.get(targetIndexNo).getName() );
viewFlag = true;
}
mViewSwitcher.showNext();
} else {
if ( --targetIndexNo < 0 ) {
targetIndexNo = mFileNameList.size() - 1;
}
if ( viewFlag ) { // image1が表示されているので image2にセット
setImage( imageView2, "image/" + mFileNameList.get(targetIndexNo).getName() );
viewFlag = false;
} else {
setImage( imageView1, "image/" + mFileNameList.get(targetIndexNo).getName() );
viewFlag = true;
}
mViewSwitcher.showPrevious();
}
}
doubleTapFlag = false;
return false;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
doubleTapFlag = true;
return false;
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
doubleTapFlag = false;
return false;
}
};
// 新設。引数を渡して、現在の幅か高さを戻り値で受け取る
private int getScreenSize( int mode ) {
int ret = -1;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // OSにより求め方が違う
WindowMetrics mWindowMetrics = this.getWindowManager().getCurrentWindowMetrics();
switch ( mode ) {
case DISPLAY_WIDTH:
ret = mWindowMetrics.getBounds().width();
break;
case DISPLAY_HEIGHT:
ret = mWindowMetrics.getBounds().height();
break;
}
} else {
WindowManager mWindowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
Display mDisplay = mWindowManager.getDefaultDisplay();
Point mRealSize = new Point();
mDisplay.getRealSize(mRealSize);
switch ( mode ) {
case DISPLAY_WIDTH:
ret = mRealSize.x;
break;
case DISPLAY_HEIGHT:
ret = mRealSize.y;
break;
}
}
return ret;
}
private void setFileNameList() {
String fName;
String[] mList = new String[0];
try {
mList = mAssetManager.list("image");
} catch (IOException e) {
e.printStackTrace();
}
for (String s : mList) {
fName = s;
fName.toLowerCase(); //小文字に変換
if ( fName.endsWith(".jpg") || fName.endsWith(".png")) { //画像ファイル選択
mFileNameList.add( new MyNumbersInString(s) );
}
}
Collections.sort(
mFileNameList, new Comparator() {
@Override
public int compare(MyNumbersInString mn1, MyNumbersInString mn2) {
return mn1.getName2().compareTo( mn2.getName2() );
}
}
);
}
private void setImage( ImageView iView, String fName ) {
try {
InputStream istream = mAssetManager.open(fName); // いずれアセットマネージャーでなくなる
Bitmap mBitmap = BitmapFactory.decodeStream(istream);
if ( mBitmap != null ) {
if ( realSizeFlag ) { // real mode
iView.setImageBitmap(mBitmap);
setPaddingImageView( iView, mBitmap.getWidth(), mBitmap.getHeight() );
} else { // fit mode
float f;
Bitmap tempBitmap = null; // 90度回転用作業ビットマップ
if ( pageModeFlag ) { // one page mode
Matrix matrix = new Matrix(); // 回転クラス
int sysOri = getOrientation(); // デバイスがポートか、ランドか
int iShape = getImageShape( mBitmap.getWidth(), mBitmap.getHeight() ); // 画像がポートか、ランドか
if ( ( ( sysOri == Configuration.ORIENTATION_PORTRAIT ) && // システムがポート、画像がランドの時
( iShape == Configuration.ORIENTATION_LANDSCAPE ) )
) {
matrix.setRotate(90, mBitmap.getWidth(), mBitmap.getHeight()); // 角度と領域を指定
} else if ( ( sysOri == Configuration.ORIENTATION_LANDSCAPE ) && // 別の条件の時
( iShape == Configuration.ORIENTATION_PORTRAIT )
) {
matrix.setRotate(270, mBitmap.getWidth(), mBitmap.getHeight()); // 別の角度と領域を指定
}
if ( sysOri != iShape ) { // ポート、ランド、双方が違う時に回転する
tempBitmap = Bitmap.createBitmap(mBitmap, 0, 0, // 元画像を回転
mBitmap.getWidth(), mBitmap.getHeight(), matrix, true);
mBitmap.recycle(); // 元々のメモリ領域を回収
mBitmap = tempBitmap; // 作業用のビットマップメモリに参照場所を移す。関数内で確保領域だからリーク少ない?
}
}
f = setImageViewFit(iView, mBitmap.getWidth(), mBitmap.getHeight()); // フィット用の倍率を求める
int mWidth = (int)( (float) mBitmap.getWidth() * f ); // 画像サイズの幅か高さをデバイスに合わせる
int mHeight =(int)( (float) mBitmap.getHeight() * f );
Bitmap scaleBitmap = Bitmap.createScaledBitmap( mBitmap, mWidth, mHeight,true ); // サイズ変更
iView.setImageBitmap(scaleBitmap);
setPaddingImageView( iView, scaleBitmap.getWidth(), scaleBitmap.getHeight() ); // 余白を設定
}
}
istream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void setPaddingImageView( ImageView iView, int bx, int by ) {
int displayWidth = getScreenSize(DISPLAY_WIDTH); // 現在のデバイス幅を取得
int displayHeight = getScreenSize(DISPLAY_HEIGHT); // 現在のデバイス高さを取得
int paddingX, paddingY;
if ( bx < displayWidth ) {
paddingX = (displayWidth - bx) / 2;
} else paddingX = 0;
if ( by < displayHeight ) {
paddingY = ( displayHeight - by ) / 2;
} else paddingY = 0;
iView.setPaddingRelative( paddingX, paddingY, paddingX, paddingY ); // イメージビューに Padding を設定
}
private float setImageViewFit( ImageView iView, int bx, int by ) {
int displayWidth = getScreenSize(DISPLAY_WIDTH); // 現在のデバイス幅を取得
int displayHeight = getScreenSize(DISPLAY_HEIGHT); // 現在のデバイス高さを取得
// デバイスの大きさを画像のサイズで割る意味は、その倍率に画像サイズを掛けるとデバイスのサイズになる
// 幅、高さの倍率の大きさを比較すると、どっちを基準にするか分かる
float fX = (float) displayWidth / (float) bx;
float fY = (float) displayHeight / (float) by;
float ret = 1f;
if ( ( ( bx > displayWidth ) && ( by > displayHeight ) ) // 画面サイズより画像サイズが大きい
|| ( ( bx < displayWidth ) && ( by < displayHeight ) ) ) { // 画面サイズより画像サイズが小さい
if ( fX > fY ) {
ret = fY; // 幅の倍率が大きければ、高さの倍率を基準にする
} else {
ret = fX; // 高さの倍率が大きければ、幅の倍率を基準にする
}
} else if ( ( bx > displayWidth ) && ( by < displayHeight ) ){ // 画像の幅を画面の幅に合わせるので
ret = fX;
} else if ( ( bx < displayWidth ) && ( by > displayHeight ) ) { // 画像の高さを画面の高さにに合わせるので
ret = fY;
}
return ret; // 戻す倍率は基準となる1つだけ、幅、高さを掛ければ、どっちかが画面のサイズになる
}
public int getOrientation() { // デバイスが、縦か、横持ちか返す
Resources resources = getResources();
Configuration config = resources.getConfiguration();
return config.orientation; // Configuration.ORIENTATION_PORTRAIT
}
public int getImageShape( int x, int y ) { // 画像が縦長か、横長か返す
int ret = 0;
if ( x > y ) {
ret = Configuration.ORIENTATION_LANDSCAPE;
} else {
ret = Configuration.ORIENTATION_PORTRAIT;
}
return ret;
}
@Override // 回転されて再描画が起こった。イメージビューを再設定
public void onConfigurationChanged( Configuration newConfig ) {
super.onConfigurationChanged(newConfig);
if ( viewFlag ) { // image1が表示されている
setImage( imageView1, "image/" + mFileNameList.get(targetIndexNo).getName() );
} else { // image2が表示されている
setImage( imageView2, "image/" + mFileNameList.get(targetIndexNo).getName() );
}
}
}
【activity_fullscrenn.xml】
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/fullscreenBackgroundColor"
android:theme="@style/ThemeOverlay.MyTest2.FullscreenContainer"
android:configChanges="orientation|screenSize" <-- ここの部分を書き足し -->
tools:context=".FullscreenActivity">
<ViewSwitcher
android:id="@+id/viewSwither"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
参考文献
Android Studio : ViewSwitcher とフリックによる画面切り替え。
ViewSwitcherで2つのViewをなめらかに切り替える。
【Android】画面タッチイベントを実装する。
【 Android アプリ開発 】全画面表示を行う方法 ( 通知バー非表示 )
Android: 画面サイズよりも大きいViewを縦/横/斜めでスクロールする。