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

android OS & iPadOS の記録。

記録5:NestedScrollView デベロッパーで推奨

2021-07-11 02:12:48 | Android studio 日記

 縦スクロールと横スクロールを入れ子にして、斜めのスクロールを実現するためのクラス。

 

【MyScrollView.java】

public class MyScrollView extends NestedScrollView {

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

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

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

    @Override
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept){

    }

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

}

 

【xml】
<?xml version="1.0" encoding="utf-8"?>
<com.packagename.testviewer3.MyScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <HorizontalScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            tools:ignore="ObsoleteLayoutParam">

            <ImageView
                android:id="@+id/image_view1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:ignore="ContentDescription" />

        </LinearLayout>
    </HorizontalScrollView>
</com.packagename.testviewer3.MyScrollView>

 

フルスクロール参考

Android: 画面サイズよりも大きいViewを縦/横/斜めでスクロールする

 

 装飾を省いた画像表示の基礎部分を記録。

 


記録4:ViewSwitcher で画像を切り替え。

2021-07-11 01:26:36 | Android studio 日記

 単純に画像切り替えなら、ImageSwitcher だけど、画像の大きいものをスクロールさせる機能を付けるなら ViewSwitcher だろう。レイアウトの xml ファイルを2つ用意し、それぞれに ScrollView を記述。ImageView にファイル名リストから次の画像を読み出しセットして、ViewSwitcher で切り替える。切り替え時のアニメーションの種類が有るようなのでそのうち試す。

 

public class MainActivity extends AppCompatActivity {

    private ImageView imageView1, imageView2;

    private ViewSwitcher mViewSwitcher;
    private MyScrollView mMSV1, mMSV2;

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

        mMSV1 = (MyScrollView) getLayoutInflater().inflate(R.layout.image1, null); // image1.xml を設定
        mMSV2 = (MyScrollView) getLayoutInflater().inflate(R.layout.image2, null); // image2.xml を設定

        mViewSwitcher = (ViewSwitcher) findViewById(R.id.viewSwitcher);

        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));

        imageView1 = findViewById(R.id.image_view1); // image1.xml のid.image_view1
        imageView2 = findViewById(R.id.image_view2); // image2.xml のid.image_view2

    }

    @Override
    protected void onResume() {
        super.onResume();
        setImage( imageView1, fullPathName[ index ] ); // フルパス画像ファイル名から imageView へ画像をセット
        setImage( imageView2, fullPathName[ index ] ); // 実際は配列と標的Noを使ってクラスメソッドを呼び引数を渡す
   }

////// タッチイベントで次の画像をセットして、ViewSwitcherでビューを切り替える。
     if ( 画面右側をタップ ) {
        setNextImage();
        mViewSwitcher.showNext(); // 次を表示
     } else {
        setNextImage();
        mViewSwitcher.showPrevious(); // 戻って表示
     }
///////


    private void setNextImage() {
        if (mViewSwitcher.getNextView() == mMSV1) { // 次の切り替えビューを確認
            setImage( imageView1, fullPathName[ ++index ] ); // ViewSwitcher.addView(view, 0); に登録したもの
        } else {
            setImage( imageView2, fullPathName[ --index ] ); // ViewSwitcher.addView(view, 1); に登録したもの
        }
    }

    private void setImage(ImageView iView, String fullPathName) {

       // 受け取ったフルパスのファイル名から画像データを読み取り、iView へ設定する。
       // 基礎部分

    }

*注意:setImage( imageView1, fullPathName[ ++index ] ); の "++index" は概念であり、実際は配列参照の範囲内かチェックする。

 

【activity_main.xml】

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_activity"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?attr/fullscreenBackgroundColor"
    android:theme="@style/ThemeOverlay.TestViewer3.FullscreenContainer"

    android:configChanges="orientation|screenSize"
    tools:context=".MainActivity">


    <LinearLayout
        android:id="@+id/L_Layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <ViewSwitcher
            android:id="@+id/viewSwitcher"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </LinearLayout>

</android.support.design.widget.CoordinatorLayout>

 

 

【image1.xml】

<?xml version="1.0" encoding="utf-8"?>
<com.packagename.testviewer3.MyScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <HorizontalScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <LinearLayout
            android:id="@+id/L_Layout1"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            tools:ignore="ObsoleteLayoutParam">

            <ImageView
                android:id="@+id/image_view1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:ignore="ContentDescription" />

        </LinearLayout>
    </HorizontalScrollView>
</com.packagename.testviewer3.MyScrollView>

 

 

【image2.xml】

<?xml version="1.0" encoding="utf-8"?>
<com.packagename.testviewer3.MyScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <HorizontalScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <LinearLayout
            android:id="@+id/L_Layout2"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            tools:ignore="ObsoleteLayoutParam">

            <ImageView
                android:id="@+id/image_view2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:ignore="ContentDescription" />

        </LinearLayout>
    </HorizontalScrollView>
</com.packagename.testviewer3.MyScrollView>

 

続く。

 


記録3:ScrollView階層下のタップ処理。GestureDetectorとdispatchTouchEvent()

2021-07-11 00:50:02 | Android studio 日記

 Activity で ScrollView の子の View でタップ処理をするためにGestureListener を設定して GestureDetector を dispatchTouchEvent() で呼ぶ。フルスクリーンの画像表示では、ダブルタップ、ロングプレスでフラグメントを開くのが良いと思う。Detector.setOnDoubleTapListener(GestureListener); は楽だ。

 タップ処理の基礎。または、layout の HorizontalScrollView で id を設定して ソースでOnTouchListener()を組んで onTouch() をオーバーライドでも行けるかな。

 

public class MainActivity extends AppCompatActivity {

    private GestureDetectorCompat mDetector;
    private final MyGestureListener mGestureListener = new MyGestureListener();


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


        mDetector = new GestureDetectorCompat(this, mGestureListener);
        mDetector.setOnDoubleTapListener(mGestureListener);
    }

    @Override // タッチイベントが取得できる
    public boolean dispatchTouchEvent(MotionEvent event) {
        super.dispatchTouchEvent(event);
        mDetector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }

    class MyGestureListener extends GestureDetector.SimpleOnGestureListener {

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {

            return false;
        }

        @Override
        public boolean onDoubleTap(MotionEvent e) {

            return false;
        }

        @Override
        public boolean onDoubleTapEvent(MotionEvent e) {

            return false;
        }

        @Override
        public void onLongPress(MotionEvent e) {

        }

        @Override
        public boolean onDown(MotionEvent e) {

            return false;
        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {

            return false;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

            return false;
        }

        @Override
        public void onShowPress(MotionEvent e) {

        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            return false;
        }
    }
}

 

続く。


記録2:フォルダ内のファイル名リストアップとソート。

2021-07-11 00:21:24 | Android studio 日記

 フォルダ内のファイルをリストアップ。android studio でフォルダの所在がはっきりしていて、リスト配列が用意されている AssetManager を使っている。アプリではデータフォルダのフルパスを取得してリスト配列を作成するメソッドに差し替える。作成クラスの配列のソートはそのまま利用できる。

 フォルダ内の画像ファイル名をリストアップして順番に表示する為の基礎部分。

 

public class MainActivity extends AppCompatActivity {

    private final ArrayList<MyNumbersInString> mFileNameList = new ArrayList<>();
    private AssetManager mAssetManager;
    private int targetIndexNo;

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

        targetIndexNo = 0;
        mAssetManager = getResources().getAssets();
        setFileNameList();

    }

    private void setFileNameList() {

        // mFileNameList.clear(); // 配列を初期化する必要がある時
        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());
                    }
                }
        );

    }
}

 

【MyNumbersInString.java】

public class MyNumbersInString {
    private String name1 = ""; // 元のファイル名
    private String name2 = ""; // 漢字、数字混在のとき、半角数字を前方を"0"で埋めた8桁に修正

    /*
        ArrayList<> で、ファイル名をソートするための準備。name2を判定条件に使う
    **/

    public MyNumbersInString(String name ){
        name1 = name;

        StringBuilder sb = new StringBuilder(name);
        String[] msplit1 = sb.toString().split( "[^\\d]" ); // 数字以外で分割
        String[] msplit2 = sb.toString().split( "\\d" );   // 数字で分割

        boolean mFlag = true;
        sb = new StringBuilder();

        // 1つの文字列を同条件反転分割しているので[0]のみ、どちらか必ず文字が入っている

        if (msplit1[0].length() == 0) {
            //mFlag = true;
            sb.append(msplit2[0]); // 文字を積む
        }
        if (msplit2[0].length() == 0) {
            mFlag = false;
            sb.append( zeroCompensation( msplit1[0]) ); // 0補填をして数字を積む
        }

        // 数字の次は文字、文字の次は数字、フラグで切り替え積んでいく。数字は0補填
        int i = 0, j = 0, len;
        while ( ( i < msplit1.length ) && ( j < msplit2.length ) ) {
            if (mFlag) { // 直前が数字でなかった
                if ( ++i < msplit1.length ) {
                    if (msplit1[i].length() != 0) { // 数字が現れた
                        sb.append( zeroCompensation( msplit1[i] ) );
                        mFlag = false;
                    }
                }
            } else { // 直前が文字でなかった
                if ( ++j < msplit2.length ) {
                    if (msplit2[j].length() != 0) { // 文字が現れた
                        sb.append(msplit2[j]);
                        mFlag = true;
                    }
                }
            }
        }

        name2 = sb.toString();
    }
    public String getName(){
        return name1;
    }
    public String getName2(){
        return name2;
    }

    private String zeroCompensation(String text){
        StringBuilder sb = new StringBuilder();
        int len = text.length(); // 桁数
        if ( len < 8 ) { // 8桁以下なら0を前に付けて8桁に合わせる
            len = 8 - len;
            for (int c = 0; c < len; c++) {
                sb.append("0");
            }
        }
        sb.append( text );
        return sb.toString();
    }
}

 

"123abc123.jpg" ファイル名とすると、

      msplit1(数字以外で分割)  msplit2(数字で分割)
1       "123"                               ""
2       ""                                     ""
3       ""                                     ""
a       ""                                     "abc"
b       "123"                                ""
c        ""                                     ""
1        ""                                     ""
2        ""                                     ".jpg"
3        ""
.
j
p
g

分割された文字列のイメージ。数字部分を抽出して"0"を足して8桁にする。そして、分割文字を組み直してファイル名を作っている。

"00000123abc00000123.jpg" と 、"123abc123.jpg" は、紐づけられていて前者を元に並べ替えをさせる。

メソッドで呼び出すのは、"123abc123.jpg" 実ファイル名の方。

続く。