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

android OS & iPadOS の記録。

基礎。ImageSwitcher 【 GestureDetectorCompat 、ImageSwitcher と OverScroller 】

2022-01-13 23:14:05 | Android studio 日記

次にImageSwitcher について。
Bitmap を bitmapDrawable に変換して、mImageSwitcherにセットするだけ。
次にセットした画像を前に表示しているものとアニメーションで交換してくれる。(検索:AnimationUtils)

ImageView view;
view = (ImageView)mImageSwitcher.getCurrentView(); // 表示View
view = (ImageView)mImageSwitcher.getNextView()     // 待機View

int imageWidth = view.getDrawable().getIntrinsicWidth();
int scrollOffsetX = view.getScrollX();

何となく、セットした画像サイズ、オフセットが取り出せる。
imageView.setScaleType() でフィット表示させていて、スクロール処理に入っちゃうとまずいことになる。
フィットモードの時はスクロールをはじくこと。
view.getDrawable().getIntrinsicWidth()は元画像のサイズを返すから正常にスクロールしない。

 

public class MainActivity extends AppCompatActivity {
    private ImageSwitcher mImageSwitcher = null;
    private AnimationSet mAnimationSet;

    private ImageView.ScaleType imageViewScaleType = ImageView.ScaleType.MATRIX;

    private BitmapDrawable bitmapDrawable;
    private Bitmap mBitmap = null, mBitmap0 = null;
    private boolean flag = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mImageSwitcher = findViewById(R.id.image_switcher);

        mImageSwitcher.setFactory(new ViewSwitcher.ViewFactory() {
            @Override
            public View makeView() {
                ImageView imageView = new ImageView(getApplicationContext());
                imageView.setScaleType(imageViewScaleType);
                return imageView;
            }
        });

        setNextAnimation();

        File f = getExternalStoragePublicDirectory(DIRECTORY_PICTURES);
        File f1 = new File(f.getAbsolutePath() + "/image1/182.jpg");
        File f2 = new File(f.getAbsolutePath() + "/image1/1.jpg");

        mBitmap0 = BitmapFactory.decodeFile(f1.getAbsolutePath());
        mBitmap = BitmapFactory.decodeFile(f2.getAbsolutePath());

        bitmapDrawable = new BitmapDrawable( getResources(),mBitmap );
        mImageSwitcher.setImageDrawable(bitmapDrawable);

        setPaddingImageView( (ImageView) mImageSwitcher.getNextView(), mBitmap.getWidth(), mBitmap.getHeight() );
    }

    public void loadImage(int y) { // タッチイベントで呼べば、切り替えをしてくれる。今回省略。

        if ( y < 400 ) setNextAnimation();
        else setPrevAnimation();

        if (flag) {
            setPaddingImageView( (ImageView) mImageSwitcher.getNextView(), mBitmap0.getWidth(), mBitmap0.getHeight() );
            mImageSwitcher.setImageDrawable(new BitmapDrawable(getResources(), mBitmap0));
        } else {
            setPaddingImageView( (ImageView) mImageSwitcher.getNextView(), mBitmap.getWidth(), mBitmap.getHeight() );
            mImageSwitcher.setImageDrawable(new BitmapDrawable(getResources(), mBitmap));
        }
        flag = !flag;
        mImageSwitcher.getCurrentView().scrollTo( 0,0 );
    }

    private void setNextAnimation() { // resフォルダ内に anim フォルダを作り、next_in_animation_set.xml ファイルを作る。
        mImageSwitcher.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.next_in_animation_set));
        mImageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.next_out_animation_set));
    }

    private void setPrevAnimation() {
        mImageSwitcher.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.prev_in_animation_set));
        mImageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.prev_out_animation_set));
    }


    public void setPaddingImageView(ImageView view, int bx, int by) {

        int screenWidth = getScreenWidth();
        int screenHeight = getScreenHeight();
        int paddingX, paddingY;
        if (bx < screenWidth) {
            paddingX = (screenWidth - bx) / 2;
        } else paddingX = 0;
        if (by < screenHeight) {
            paddingY = (screenHeight - by) / 2;
        } else paddingY = 0;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            view.setPaddingRelative(paddingX, paddingY, paddingX, paddingY);
        } else
            view.setPadding(paddingX, paddingY, paddingX, paddingY);
    }

    public int getScreenWidth() {
        WindowManager wManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            WindowMetrics mWindowMetrics = wManager.getMaximumWindowMetrics();
            return mWindowMetrics.getBounds().width();
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            DisplayMetrics mDisplayMetrics = new DisplayMetrics();
            wManager.getDefaultDisplay().getRealMetrics(mDisplayMetrics);
            return mDisplayMetrics.widthPixels;
        }
        Point realSize = new Point();
        wManager.getDefaultDisplay().getSize(realSize);
        return realSize.x;
    }

    public int getScreenHeight() {
        WindowManager wManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            WindowMetrics mWindowMetrics = wManager.getCurrentWindowMetrics();
            return mWindowMetrics.getBounds().height();
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            DisplayMetrics mDisplayMetrics = new DisplayMetrics();
            wManager.getDefaultDisplay().getRealMetrics(mDisplayMetrics);
            return mDisplayMetrics.heightPixels;
        }
        Point realSize = new Point();
        wManager.getDefaultDisplay().getSize(realSize);
        return realSize.y;
    }

}

【next_in_animation_set.xml】下から上に移動指示。

< ?xml version="1.0" encoding="utf-8"?>
< set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="@android:anim/decelerate_interpolator">

    < translate
        android:fromYDelta="100%"
        android:toYDelta="0%"
        android:fillAfter="true"
        android:duration="250" />

< /set>

他は省略。


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

基礎。GestureDetectorCompat 【 GestureDetectorCompat 、ImageSwitcher と OverScroller 】

2022-01-13 22:52:50 | Android studio 日記

まず、ジェスチャーのおさらい。
onTouchEvent()からのフックとオーバーライド。
タップ処理をここで完結させるには、true を返す。

public class MainActivity extends AppCompatActivity {

    private GestureDetectorCompat mDetector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mDetector = new GestureDetectorCompat(this, new MyGestureListener() );

    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if ( mDetector.onTouchEvent(event) ) return true;
        return super.onTouchEvent(event);
    }


    class MyGestureListener extends GestureDetector.SimpleOnGestureListener {

        @ Override
        public boolean onDown(MotionEvent event) {
            return false;
        }

        @Override
        public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX, float distanceY) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
            return true;
        }
        @Override
        public boolean onSingleTapConfirmed(MotionEvent event) {
            return true;
        }

    };

}

目標のビューの onTouchEvent() に Detector.onTouchEvent() を寄生させタップ処理をさせる。
ScrollViewの重ね掛け以外は普通に使えるんだけど。

 

3部構成の一部部分は省略掲載になっている。だが、プログラムを全部組み合わせると、とりあえずテストできる状態になる。プロジェクトの設定状態では問題が起こるかもしれないが…。

フリンクしてスクロールさせる時は滑ってパンさせる事を推奨しているらしいので組み込んだ。

 


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

再確認。image viewer 制作。

2022-01-12 14:43:17 | Android studio 日記

自分の知識範囲で画像表示アプリを作ろうとしてきた。
色々と試験をしてきて考えがぼやけてきた所があるので確認と開発の方向を求める。

まず、仕様。
1、ディレクトリを移動する。ディレクトリ内に画像があれば代表サムネイルをアイコンに使用。
2、ディレクトリ内の画像ファイルをサムネイル表示して画像を選択する。
3、ブックマークを挿入、管理する。
4、画像表示、1枚、2枚、フィットサイズ、オリジナルサイズ。
5、プリファレンスに一部情報を保存。ブックマークなど。

基本の画像表示について。
問題は、メモリ消費。オリジナルサイズで2枚並べて表示する事は古いデバイスではストップする確率は高い。スクリーンサイズの大きさでポートレート形状2枚並びの表示を基本にする。
タップ操作により、オリジナルサイズ1枚の表示に切り替えるモードを作る。

サムネイル表示について。
10枚程度のサムネイル画像処理なら時間は短い。枚数が多くなるほど待ち時間が長くなり気になる。
キャッシュ等の対応を考える。ディレクトリ内の画像ファイルの移動や名前変更でリンクが切れた時の更新を考える。

 

画像表示の補足。
オリジナルサイズがスクリーンサイズより大きい時の画像スクロール。scrollView とスイッチャーの相性が今一で動作が思い通りにならない。タップ処理も複雑に絡んで分かりづらい。
スイッチャーは、viewSwitcher と imageSwitcherがある。viewSwitcher はイメージ、ボタン、テキストなどレイアウトごとに切り替えるもの。imageSwitcher は imageView を切り替えるもの。画像単体を切り替えるなら imageSwitcher が向いている。imageSwitcher と gestureDetector でタップと画像の処理をまとめられる。
画像表示の基本はフィットサイズで imageSwitcher を使い、切り替える。オリジナル表示は imageView で1枚を取り扱う別構成にする。のもいいかな。

 

 

デベロッパーリファレンスは初心者には難しい。サンプルとのリンクがほぼない。というか知りたいことが見つけられない。Web検索でもデベロッパーリファレンスの狭い範囲を解説しているもので実際のアプリに組み込むには開発者にある程度のレベルが求められる。助かりますが。「初心者向け」の看板に初心者向け?と思ってしまう。
アプリの系統で要点説明して欲しい…。それは有料講座で勉強してくださいという事か(笑)

数をこなしてなんぼ。なんだけど、手掛かりが無いのは辛い。


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

現状記録。Jellybean は、表示画像サイズ強制修正か?

2022-01-07 21:26:20 | Android studio 日記

Jellybean 実機テストで元画像が 1,200x1,800 ドット2枚 canvas 合成で表示できない。
1,000x1,800 2枚合成なら表示される。

合成ではなく、LinearLayout で imageview を2枚並べるならどうか?
簡易モデルを作ってテストしたが、scrollview を使って画像2枚のスクロールはOK。
本来のプロジェクトに組み込むとエラーが噴出…。また、スライドでスクロールはできる。
しかし、imageview 2枚横並び表示でスクロール位置も指定できない(分からない)。
そして、実機テストまで行けない…。

ViewSwitcher は便利だが、メモリ容量が多い新機種用かな?
似たような効果の ImageSwitcher は、切り替えアニメーション設定が直感的で好感触。
ImageSwitcher に BitmapDrawable を入れれば、指定アニメーションで切り替え完了。
canvas を渡すこともできる。
しかし、画像サイズの違うファイルを切り替えると、大きいサイズの次に小さいサイズが表示された時に空白が表れる。その後に同じ画像を表示すると空白は消えてスクリーン枠に張り付く。症状の原因は分からず。
アニメーションの動作は面白いのでもう少し調べる。

あと、ImageView 自体にアニメーションを施せる。メソッドで効果をまとめて上手く使えれば、メモリ消費を抑えられるかもしれない。

2つの画像を並べて表示、これは鉄板なので canvas 合成からの ImageView に設定する事を基本に考える。
その ImageView をアニメーションで切り替える。それでダメならOSバージョンで分岐して画像サイズ制限で勝手に縮小処理だ。

 

追記。

ImageSwitcher で画像を切り替えた時、サイズが大きいものから小さいものに変わると空白が表示される現象の対策。

ImageSwitcher 初期設定で ImageView に次の一文を付け足す。拡縮無し表示。
imageView.setScaleType(ImageView.ScaleType.MATRIX);


        mImageSwitcher = findViewById(R.id.image_switcher);

        mImageSwitcher.setFactory(new ViewSwitcher.ViewFactory() {
            @Override
            public View makeView() {
                ImageView imageView = new ImageView(getApplicationContext());
                imageView.setScaleType(ImageView.ScaleType.MATRIX);

                return imageView;
            }
        });

 

スクリーン左上に合わせて表示される。


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

実機テスト。Android 4.2 jelly bean

2022-01-03 12:53:11 | Android studio 日記

エミュレーターでは minレベル16で実行。
大きな問題もなく動作しているので実機でテストする。

実機はメモリ少ない。性能低い。処理データは多い。
1、recyclerView の表示までの処理時間が長かった。
2、元画像が1200x1800で2枚並べた表示が白画像だけに…次画像へ移る前に停止。

recyclerView はキャッシュとか使わないとだめだろうか。無駄もまだ多いので再考。
2枚表示はメモリ不足か…。canvas で画像2枚を合成しているがキャンバスサイズを2000x1800で合成すれば画像表示はできる。2100x1800では白画面表示。条件分岐でエラー処理したけど、bitmapは問題なさそう。
対応はサイズ制限をするか、表示方法を変更するか。キャンバス合成でなく、imageView 2枚並べてそれぞれに設定してメモリ消費を回避。LinearLayout をview.scrollBy() させれば…。あ、imageViewのスクロールとは違うのだった。
ま、何とかなるだろう。

 


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする