タブレット用プログラムの書き止め

android OS & iPadOS の記録。

なぜか、ImegeView の scaleType が作動しないので自作

2021-06-25 13:52:58 | Android studio 日記

 画像のリアルサイズモード、フィットサイズモード切り替え。完成ではない。アクションが決まらない。表示だけができた。
 デバイスがポートレート表示(縦長)で画像がランドスケープ表示(横長)だとフィットモードは小さく表示されてしまうので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を縦/横/斜めでスクロールする。