20200626のAndroidに関する記事は5件です。

React Nativeで画面回転時のレイアウト崩れに対応したら、KeyboardAvoidingViewが効かなくなった

以下の2本立てです。

  • React Nativeで画面回転したらAndroidの場合にレイアウトが崩れてしまったので対応した
  • 今度はKeyboardAvoidingViewが効かなくなったので代替策で回避した

環境

  • React Native 0.61.5
  • iOS 13.5.1
  • Android 10

React Nativeで画面回転したらレイアウト崩れが発生した

KeyboardAvoidingViewをrootに配置した画面をPortrait=>Landscape=>Portraitと回転させると、謎の空間が発生。AndroidでFlexが正しく動いていないような挙動をしました。

名称未設定_001.png

ソースはこのような感じです。

対応前
class Hoge extends React.Component {
  render() {
    return (
      <KeyboardAvoidingView
        style={{
          flex: 1
        }}
        behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
      >
        // ...
      </KeyboardAvoidingView>
    );
  }
);

色々と解決方法を探して手当り次第試してみたところ、StackOverflowで見つけた方法で、stateを介して再renderさせるようにすることで正しくレイアウトされるようになりました。

対応後
class Hoge extends React.Component {
  _onLayout = () => {
    this.setState({ width: Dimensions.get('window').width }); 
  }

  render() {
    return (
      <KeyboardAvoidingView
        onLayout={this._onLayout}
        style={{
          flex: 1,
          width
        }}
        behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
      >
        // ...
      </KeyboardAvoidingView>
    );
  }
);

これにて一件落着・・と思いきや、、

今度はKeyboardAvoidingViewが効かなくなった

上記の対応を行うことで、iOS・Androidともに、KeyboardAvoidingViewがキーボードを避けないただのViewと化してしまいました。

Viewの入れ子関係を入れ替えたり、色々試してみたがうまくいかず。結局KeyboardAvoidingViewをあきらめ、代わりにKeyboardSpacerというライブラリを使うとうまくいきました。

対応後(改)
class Hoge extends React.Component {
  _onLayout = ({nativeEvent}) => {
    const width = Dimensions.get('window').width;
    const height = Dimensions.get('window').height;
    const screenOffset = height - nativeEvent.layout.height;
    this.setState({ width, screenOffset });
  };

  render() {
    return (
      <View
        onLayout={this._onLayout}
        style={{
          flex: 1,
          width
        }}
        behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
      >
        // ...
        <KeyboardSpacer topSpacing={(-1) * this.state.screenOffset} />
      </View>
    );
  }
);

はじめはAndroidで思うように機能しませんでしたが、AndroidManifestに windowSoftInputMode="adjustResize" を指定するとうまく動くようになりました。

また、ReactNavigationのBottomTabNavigatorを使用しているため、WindowのサイズとViewのサイズの差分を計算し、 KeyboardSpacertopSpacing に設定しています。

おわりに

画面回転つながりで、iPhoneでLandscapeにしたときにステータスバーが消える影響でレイアウトが崩れる問題も発生していたので、ステータスバーの高さをstoreで管理するようにしたりしました。
こういう小細工が色々と必要なのがツラいところです。

そろそろ温泉にでも行きたいですねぇ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Android9.0 Pie Java】チャットアプリで横スワイプ→ダイアログ表示→削除を実装する

環境

Android9.0 Pie Java

はじめに

最近Android Javaでチャットアプリを作成していまして、LINE風のチャット一覧削除を実装しました。
RecyclerViewのリスト表示と削除機能の記事は結構ありますが、

横スワイプ→ダイアログ表示→削除
MainActivity + 複数のFragment構成

の実装例は日本語の記事では見つからなかったので共有させて頂きます。
(ベストプラクティスかは怪しいので参考程度にお願いします。。ご指摘大歓迎です!)

こんな実装ができます
243e5a5ccb079ad0d385004d69a930ba.gif

完成品URL

非常にコンテンツが長いので、完成品を取り合えず手に入れたい方はこちらからどうぞ。
https://github.com/yuta-matsumoto/chat

ディレクトリ構成

ビルドファイルやマニフェストファイルは省略します

Chat
 ├app/src/main/
      ├java/
      │ └com.example.chat/
      │         ├fragments/
      │         │    ├BaseFragment.java
      │         │    ├ChatListFragment.java
      │         │    └DeleteChatFragment.java
      │         ├helpers/
      │         │    ├ChatListAdapter.java
      │         │    ├ViewHolder.java
      │         │    └SwipeHelper.java
      │         ├models/
      │         │    ├ChatRowData.java
      │         │    └DeleteChatRow.java
      │         └MainAcitivity.java
      ├res/
      │ ├drawable/
      │ │   └sample1.png(以下省略)
      │ ├layout/
      │ │   ├activity_main.xml
      │ │   ├chat_list_row.xml
      │ │   └fragment_chat_list.xml
      │ └values/
      │     ├colors.xml
      │     ├strings.xml
      │     └styles.xml

コード

依存関係

build.gradle
dependencies {
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation 'androidx.recyclerview:recyclerview:1.1.0' // 追記
    implementation 'androidx.cardview:cardview:1.0.0' // 追記
}

Activity

MainActivityはFragmentを読み込むだけにしています。
FragmentをBaseFragmentという全てのFragmentのベースクラスを継承して MainActivity + 複数のFragment構成 を実現しています。
※チャット一覧画面→チャット画面のFragment切り替えで必要でした。
 暇を見つけて続きのチャット画面の記事もその内共有したいと思います。

以下の記事を参考にしています。
https://www.slideshare.net/olrandir/android-the-single-activity-multiple-fragments-pattern-one-activity-to-rule-them-all

MainActivity.java
package com.example.chat;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import com.example.chat.fragments.BaseFragment;
import com.example.chat.fragments.ChatListFragment;

public class MainActivity extends AppCompatActivity {
    // Fragmentのベース
    private BaseFragment fragment;

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

        // 初回はチャット一覧のFragmentをセット
        if (fragment == null) {
            fragment = new ChatListFragment();
        }
        // main_activityにFragmentをセット
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.mainContainer, fragment)
                .commit();
    }
}

Fragment

ベースとなるFragmentです。
今回は入れていませんが、共通となるボタンのイベントリスナー等をBaseFragmentに入れてしまうとコンパクトになるので便利です。

BaseFragment.java
package com.example.chat.fragments;

import android.os.Bundle;
import androidx.fragment.app.Fragment;

/**
 * ベースとなるFragment
 */
public abstract class BaseFragment extends Fragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}

チャットリスト画面のFragmentです。

ChatListFragment.java
package com.example.chat.fragments;

import android.graphics.Color;
import android.os.Bundle;

import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.chat.models.DeleteChatRowData;
import com.example.chat.helpers.ChatListAdapter;
import com.example.chat.models.ChatRowData;
import com.example.chat.R;
import com.example.chat.helpers.SwipeHelper;

import java.util.ArrayList;
import java.util.List;

/**
 * チャット一覧画面用Fragment
 */
public class ChatListFragment extends BaseFragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_chat_list, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        RecyclerView rv = view.findViewById(R.id.recyclerView);

        // チャット一覧のデータList
        final List list = getChatList();
        // チャット一覧のデータListの要素数
        final int itemCount = list.size();

        // チャット一覧のアダプター
        final ChatListAdapter adapter = new ChatListAdapter(list) {
            @Override
            public void onItemClick(View view, int pos, List<ChatRowData> list) {
                // 行をクリックした時の処理を追記
            }
        };

        LinearLayoutManager llm = new LinearLayoutManager(getContext());

        rv.setHasFixedSize(true);

        rv.setLayoutManager(llm);

        rv.setAdapter(adapter);

        // スワイプを実装
        SwipeHelper swipeHelper = new SwipeHelper(getContext(), rv) {
            @Override
            public void instantiateUnderlayButton(RecyclerView.ViewHolder viewHolder, List<UnderlayButton> underlayButtons) {
                underlayButtons.add(new SwipeHelper.UnderlayButton(
                        getResources().getString(R.string.chat_list_delete_button_label),
                        0,
                        Color.parseColor(getResources().getString(R.string.chat_list_delete_button_color)),
                        new SwipeHelper.UnderlayButtonClickListener() {
                            @Override
                            public void onClick(int pos) {
                                FragmentManager fragmentManager = getFragmentManager();
                                DeleteChatRowFragment fragment = new DeleteChatRowFragment();
                                // 削除ダイアログfragmentに削除する行データをセット
                                DeleteChatRowData deleteChatRowData = new DeleteChatRowData();
                                deleteChatRowData.setList(list);
                                deleteChatRowData.setAdapter(adapter);
                                deleteChatRowData.setPosition(pos);
                                deleteChatRowData.setItemCount(itemCount);

                                // bundleを利用してデータを渡す
                                Bundle bundle = new Bundle();
                                bundle.putSerializable(getResources().getString(R.string.delete_dialog_list_tag), deleteChatRowData);
                                fragment.setArguments(bundle);

                                // ダイアログ表示
                                fragment.show(fragmentManager, "delete chat list");
                            }
                        }
                ));
            }
        };
    }

    /**
     * チャット一覧のテストデータ生成
     */
    private List<ChatRowData> getChatList() {
        List<ChatRowData> list = new ArrayList<>();

        ChatRowData data1 = new ChatRowData();
        data1.setName("田中太郎");
        data1.setText("こんにちは");
        data1.setMessageDateTime("2020/6/09 13:00");
        data1.setProfileImageId(R.drawable.sample1);
        list.add(data1);

        ChatRowData data2 = new ChatRowData();
        data2.setName("佐藤茂");
        data2.setText("おはようございます!");
        data2.setMessageDateTime("2020/6/08 8:10");
        data2.setProfileImageId(R.drawable.sample2);
        list.add(data2);

        ChatRowData data3 = new ChatRowData();
        data3.setName("taro");
        data3.setText("何時だっけ?");
        data3.setMessageDateTime("2020/6/07 20:09");
        data3.setProfileImageId(R.drawable.sample3);
        list.add(data3);

        ChatRowData data4 = new ChatRowData();
        data4.setName("hanako");
        data4.setText("教科書を貸してください");
        data4.setMessageDateTime("2020/6/06 07:00");
        data4.setProfileImageId(R.drawable.sample4);
        list.add(data4);

        ChatRowData data5 = new ChatRowData();
        data5.setName("たなか");
        data5.setText("無理");
        data5.setMessageDateTime("2020/6/06 01:05");
        data5.setProfileImageId(R.drawable.sample5);
        list.add(data5);

        ChatRowData data6 = new ChatRowData();
        data6.setName("小林");
        data6.setText("いいよ");
        data6.setMessageDateTime("2020/6/05 14:22");
        data6.setProfileImageId(R.drawable.sample6);
        list.add(data6);

        ChatRowData data7 = new ChatRowData();
        data7.setName("ペタジーニ");
        data7.setText("帰りたい");
        data7.setMessageDateTime("2020/6/05 13:00");
        data7.setProfileImageId(R.drawable.sample7);
        list.add(data7);

        ChatRowData data8 = new ChatRowData();
        data8.setName("Hayato");
        data8.setText("映画を見に行きましょう先輩!");
        data8.setMessageDateTime("2020/6/04 21:50");
        data8.setProfileImageId(R.drawable.sample8);
        list.add(data8);

        ChatRowData data9 = new ChatRowData();
        data9.setName("Tom");
        data9.setText("lol");
        data9.setMessageDateTime("2020/5/30 2:30");
        data9.setProfileImageId(R.drawable.sample9);
        list.add(data9);

        ChatRowData data10 = new ChatRowData();
        data10.setName("y.matsumoto");
        data10.setText("やったぜ");
        data10.setMessageDateTime("2020/5/29 4:00");
        data10.setProfileImageId(R.drawable.sample10);
        list.add(data10);

        return list;
    }
}

削除ダイアログのFragmentです。

DeleteChatRowFragment.java
package com.example.chat.fragments;

import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.TextView;

import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.recyclerview.widget.RecyclerView;

import com.example.chat.R;
import com.example.chat.models.DeleteChatRowData;

import java.util.List;

/**
 * 削除ダイアログ用Fragment
 */
public class DeleteChatRowFragment extends DialogFragment {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // setCancelable(false)でダイアログ外を押しても閉じない
        this.setCancelable(false);
        TextView title = new TextView(getContext());
        title.setText(getResources().getString(R.string.delete_dialog_message));
        title.setPadding(10, 50, 10, 10);
        title.setGravity(Gravity.CENTER);

        return new AlertDialog.Builder(getActivity())
                .setCustomTitle(title)
                // OKが押された場合
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // 削除処理
                        Bundle bundle = getArguments();
                        DeleteChatRowData deleteChatRowData =
                                (DeleteChatRowData) bundle.getSerializable(getResources().getString(R.string.delete_dialog_list_tag));
                        List list = deleteChatRowData.getList();
                        RecyclerView.Adapter adapter = deleteChatRowData.getAdapter();
                        int pos = deleteChatRowData.getPosition();
                        int itemCount = deleteChatRowData.getItemCount();
                        // チャット一覧Listから押された行のpositionの順番の要素を削除
                        list.remove(pos);
                        // アダプターに要素を削除したことを通知
                        deleteChatRowData.getAdapter().notifyItemRemoved(pos);
                        // チャット一覧に変更があったことを通知しバインドし直す
                        adapter.notifyItemRangeChanged(pos, itemCount);
                    }
                })
                // Cancelが押された場合
                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // スワイプを戻す
                        Bundle bundle = getArguments();
                        DeleteChatRowData deleteChatRowData =
                                (DeleteChatRowData) bundle.getSerializable(getResources().getString(R.string.delete_dialog_list_tag));
                        RecyclerView.Adapter adapter = deleteChatRowData.getAdapter();
                        int pos = deleteChatRowData.getPosition();

                        // スワイプが元に戻る
                        adapter.notifyItemChanged(pos);
                    }
                })
                .create();
    }

    // アプリがバックグラウンドに回った時終了させない
    @Override
    public void onPause() {
        super.onPause();
        dismiss();
    }
}

ヘルパー

チャットの一覧表示で使用します。

ChatListAdapter.java
package com.example.chat.helpers;

import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import androidx.recyclerview.widget.RecyclerView;

import com.example.chat.R;
import com.example.chat.models.ChatRowData;

import java.util.List;

/**
 * チャット一覧表示に使用するAdapterクラス
 */
public class ChatListAdapter extends RecyclerView.Adapter<ViewHolder> {
    private List<ChatRowData> list;

    public ChatListAdapter(List<ChatRowData> list) {
        this.list = list;
    }

    /**
     * チャット一覧のViewHolderを作成する
     */
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // 一行分のlayoutをViewに読み込む
        View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_list_row, parent, false);
        final ViewHolder vh = new ViewHolder(inflate);

        // クリックリスナーを登録
        inflate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // クリックされた行のpositionを取得
                int position = vh.getAdapterPosition();
                // Viewの操作はActivityかFragmentでハンドリングしなくてはいけないので実処理は書かない
                onItemClick(v, position, list);
            }
        });

        // タッチリスナーを登録
        inflate.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // Viewの操作はActivityかFragmentでハンドリングしなくてはいけないので実処理は書かない
                return onItemTouch(v);
            }
        });
        return vh;
    }

    /**
     * ViewHolder内のViewにチャット一覧Listのデータをbindする
     */
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        String messageDateTime = list.get(position).getMessageDateTime();
        holder.nameView.setText(list.get(position).getName());
        holder.textView.setText(list.get(position).getText());
        holder.timeView.setText(messageDateTime);
        holder.profileView.setImageResource(list.get(position).getProfileImageId());
    }

    /**
     * チャット一覧Listの要素数を設定する
     */
    @Override
    public int getItemCount() {
        return list.size();
    }

    /**
     * ChatListFragmentでoverrideして処理させる
     */
    public void onItemClick(View view, int pos, List<ChatRowData> list) {
        ;
    }

    /**
     * ChatListFragmentでoverrideして処理させる
     */
    public boolean onItemTouch(View view) {
        return false;
    }
}

ViewHolder.java
package com.example.chat.helpers;

import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.recyclerview.widget.RecyclerView;

import com.example.chat.R;

/**
 * ViewHolderクラス
 * 一行分を構成するViewを定義しておく
 */
public class ViewHolder extends RecyclerView.ViewHolder {
    public TextView nameView;
    public TextView textView;
    public TextView timeView;
    public ImageView profileView;

    public ViewHolder(View itemView) {
        super(itemView);
        nameView = itemView.findViewById(R.id.name);
        textView = itemView.findViewById(R.id.text);
        timeView = itemView.findViewById(R.id.time);
        profileView = itemView.findViewById(R.id.profileImage);
    }
}

横スワイプの動きで使用します。
こちらの記事をかなり参考にしました。

https://www.it-swarm.dev/ja/android/%E3%82%B9%E3%83%AF%E3%82%A4%E3%83%97%E3%81%AErecyclerview-itemtouchhelper%E3%83%9C%E3%82%BF%E3%83%B3/833735822/amp/

SwipeHelper.java
package com.example.chat.helpers;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

/**
 * スワイプのヘルパークラス
 */
public abstract class SwipeHelper extends ItemTouchHelper.SimpleCallback {
    // スワイプで表示されるDELETEボタンのwidth
    public static final int BUTTON_WIDTH = 230;
    private RecyclerView recyclerView;
    private List<UnderlayButton> buttons;
    private GestureDetector gestureDetector;
    private int swipedPos = -1;
    private float swipeThreshold = 0.5f;
    private Map<Integer, List<UnderlayButton>> buttonsBuffer;
    private Queue<Integer> recoverQueue;

    private GestureDetector.SimpleOnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            for (UnderlayButton button : buttons) {
                if (button.onClick(e.getX(), e.getY()))
                    break;
            }

            return true;
        }
    };

    private View.OnTouchListener onTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent e) {
            if (swipedPos < 0) return false;
            Point point = new Point((int) e.getRawX(), (int) e.getRawY());

            RecyclerView.ViewHolder swipedViewHolder = recyclerView.findViewHolderForAdapterPosition(swipedPos);
            View swipedItem = swipedViewHolder.itemView;
            Rect rect = new Rect();
            swipedItem.getGlobalVisibleRect(rect);

            if (e.getAction() == MotionEvent.ACTION_DOWN
                    || e.getAction() == MotionEvent.ACTION_UP
                    || e.getAction() == MotionEvent.ACTION_MOVE) {
                if (rect.top < point.y && rect.bottom > point.y)
                    gestureDetector.onTouchEvent(e);
                else {
                    recoverQueue.add(swipedPos);
                    swipedPos = -1;
                    recoverSwipedItem();
                }
            }
            return false;
        }
    };

    public SwipeHelper(Context context, RecyclerView recyclerView) {
        super(0, ItemTouchHelper.LEFT);
        this.recyclerView = recyclerView;
        this.buttons = new ArrayList<>();
        this.gestureDetector = new GestureDetector(context, gestureListener);
        this.recyclerView.setOnTouchListener(onTouchListener);
        buttonsBuffer = new HashMap<>();
        recoverQueue = new LinkedList<Integer>() {
            @Override
            public boolean add(Integer o) {
                if (contains(o))
                    return false;
                else
                    return super.add(o);
            }
        };

        attachSwipe();
    }


    @Override
    public boolean onMove(RecyclerView recyclerView,
                          RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        return false;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        int pos = viewHolder.getAdapterPosition();

        if (swipedPos != pos)
            recoverQueue.add(swipedPos);

        swipedPos = pos;

        if (buttonsBuffer.containsKey(swipedPos))
            buttons = buttonsBuffer.get(swipedPos);
        else
            buttons.clear();

        buttonsBuffer.clear();
        swipeThreshold = 0.5f * buttons.size() * BUTTON_WIDTH;
        recoverSwipedItem();
    }

    @Override
    public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
        return swipeThreshold;
    }

    @Override
    public float getSwipeEscapeVelocity(float defaultValue) {
        return 0.1f * defaultValue;
    }

    @Override
    public float getSwipeVelocityThreshold(float defaultValue) {
        return 5.0f * defaultValue;
    }

    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView,
                            RecyclerView.ViewHolder viewHolder,
                            float dX, float dY, int actionState, boolean isCurrentlyActive) {
        int pos = viewHolder.getAdapterPosition();
        float translationX = dX;
        View itemView = viewHolder.itemView;

        if (pos < 0) {
            swipedPos = pos;
            return;
        }

        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
            if (dX < 0) {
                List<UnderlayButton> buffer = new ArrayList<>();

                if (!buttonsBuffer.containsKey(pos)) {
                    instantiateUnderlayButton(viewHolder, buffer);
                    buttonsBuffer.put(pos, buffer);
                } else {
                    buffer = buttonsBuffer.get(pos);
                }

                translationX = dX * buffer.size() * BUTTON_WIDTH / itemView.getWidth();
                drawButtons(c, itemView, buffer, pos, translationX);
            }
        }

        super.onChildDraw(c, recyclerView, viewHolder, translationX, dY, actionState, isCurrentlyActive);
    }

    private synchronized void recoverSwipedItem() {
        while (!recoverQueue.isEmpty()) {
            int pos = recoverQueue.poll();
            if (pos > -1) {
                recyclerView.getAdapter().notifyItemChanged(pos);
            }
        }
    }

    private void drawButtons(Canvas c, View itemView, List<UnderlayButton> buffer, int pos, float dX) {
        float right = itemView.getRight();
        float dButtonWidth = (-1) * dX / buffer.size();

        for (UnderlayButton button : buffer) {
            float left = right - dButtonWidth;
            button.onDraw(
                    c,
                    new RectF(
                            left,
                            itemView.getTop(),
                            right,
                            itemView.getBottom()
                    ),
                    pos
            );

            right = left;
        }
    }

    public void attachSwipe() {
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(this);
        itemTouchHelper.attachToRecyclerView(recyclerView);
    }

    public abstract void instantiateUnderlayButton(RecyclerView.ViewHolder viewHolder, List<UnderlayButton> underlayButtons);

    public static class UnderlayButton {
        private String text;
        private int imageResId;
        private int color;
        private int pos;
        private RectF clickRegion;
        private UnderlayButtonClickListener clickListener;

        public UnderlayButton(String text, int imageResId, int color, UnderlayButtonClickListener clickListener) {
            this.text = text;
            this.imageResId = imageResId;
            this.color = color;
            this.clickListener = clickListener;
        }

        public boolean onClick(float x, float y) {
            if (clickRegion != null && clickRegion.contains(x, y)) {
                clickListener.onClick(pos);
                return true;
            }

            return false;
        }

        public void onDraw(Canvas c, RectF rect, int pos) {
            Paint p = new Paint();

            // 背景色セット
            p.setColor(color);
            c.drawRect(rect, p);

            // DELETEの文字色セット
            p.setColor(Color.WHITE);
            p.setTextSize(50);

            Rect r = new Rect();
            float cHeight = rect.height();
            float cWidth = rect.width();
            p.setTextAlign(Paint.Align.LEFT);
            p.getTextBounds(text, 0, text.length(), r);
            float x = cWidth / 2f - r.width() / 2f - r.left;
            float y = cHeight / 2f + r.height() / 2f - r.bottom;
            c.drawText(text, rect.left + x, rect.top + y, p);

            clickRegion = rect;
            this.pos = pos;
        }
    }

    public interface UnderlayButtonClickListener {
        void onClick(int pos);
    }
}

モデル

チャット一覧の一行分のデータを詰めます。

ChatRowData.java
package com.example.chat.models;

/**
 * 一行分のデータモデルクラス
 */
public class ChatRowData {
    private String name;
    private String text;
    private String messageDateTime;
    private int profileImageId;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getMessageDateTime() {
        return messageDateTime;
    }

    public void setMessageDateTime(String messageDateTime) {
        this.messageDateTime = messageDateTime;
    }

    public int getProfileImageId() {
        return profileImageId;
    }

    public void setProfileImageId(int profileImageId) {
        this.profileImageId = profileImageId;
    }
}

削除ダイアログ用に必要なデータを詰めます。

ChatRowData.java
package com.example.chat.models;

/**
 * 一行分のデータモデルクラス
 */
public class ChatRowData {
    private String name;
    private String text;
    private String messageDateTime;
    private int profileImageId;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getMessageDateTime() {
        return messageDateTime;
    }

    public void setMessageDateTime(String messageDateTime) {
        this.messageDateTime = messageDateTime;
    }

    public int getProfileImageId() {
        return profileImageId;
    }

    public void setProfileImageId(int profileImageId) {
        this.profileImageId = profileImageId;
    }
}

レイアウト

activity_mainにはFragmentを入れるためのFrameLayout以外は記述しません。
本当はヘッダーとフッターも共通パーツ化してしまえばメンテナンス性も向上するのですが、

・追加予定のチャット画面への遷移アニメーション(右から画面全体にチャット画面のレイヤーが覆い被さる感じ)が中々困難になる点
・バックキーの挙動を組み合わせると地獄に陥った点

から共通パーツ化は見送りました。。
次回の記事にて有識者の方の改善策がもし聞けたら本当に嬉しいです。。

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusableInTouchMode="true"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/mainContainer"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
    </FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

チャット一覧画面用のfragment layoutです。

fragment_chat_list.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/background_light_gray"
    tools:context=".fragments.ChatListFragment">

    <View
        android:id="@+id/headerView"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:background="@color/background_dark_gray"
        android:contextClickable="false"
        android:layerType="none"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/chatListSubject"
        android:layout_width="63dp"
        android:layout_height="19dp"
        android:text="@string/chat_list_subject_label"
        android:textAlignment="center"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
        android:textColor="@color/font_color_black"
        app:layout_constraintBottom_toBottomOf="@+id/headerView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/headerView"
        app:layout_constraintVertical_bias="0.48" />

    <View
        android:id="@+id/headerBorder"
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:layout_marginTop="48dp"
        android:background="@color/background_border"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/headerView" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:isScrollContainer="false"
        app:layout_constraintBottom_toTopOf="@+id/footerBorder"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/headerView"
        app:layout_constraintVertical_bias="0.0">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
    </LinearLayout>

    <View
        android:id="@+id/background"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:background="@color/background_dark_gray"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/footerBorder" />

    <ImageButton
        android:id="@+id/homeButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="80dp"
        android:background="@color/background_transparent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/footerBorder"
        app:srcCompat="@drawable/home" />

    <ImageButton
        android:id="@+id/chatListButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/background_transparent"
        app:layout_constraintEnd_toStartOf="@+id/userButton"
        app:layout_constraintStart_toEndOf="@+id/homeButton"
        app:layout_constraintTop_toTopOf="@+id/homeButton"
        app:srcCompat="@drawable/fukidashi" />

    <ImageButton
        android:id="@+id/userButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="80dp"
        android:background="@color/background_transparent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@+id/chatListButton"
        app:srcCompat="@drawable/person" />

    <View
        android:id="@+id/footerBorder"
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:layout_marginBottom="72dp"
        android:background="@color/background_border"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

チャット一覧一行分のlayoutです。

chat_list_row.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <androidx.cardview.widget.CardView
        android:id="@+id/chatListCardView"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        app:cardCornerRadius="15dp"
        app:cardElevation="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <ImageView
            android:id="@+id/profileImage"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@mipmap/ic_launcher" />
    </androidx.cardview.widget.CardView>

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_marginStart="16dp"
        android:text="name"
        android:textColor="@color/font_color_black"
        android:textSize="12sp"
        android:textStyle="bold"
        app:layout_constraintStart_toEndOf="@+id/chatListCardView"
        app:layout_constraintTop_toTopOf="@+id/chatListCardView" />

    <TextView
        android:id="@+id/time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:text="time"
        android:textColor="@color/font_color_black"
        android:textSize="8sp"
        app:layout_constraintBottom_toBottomOf="@+id/name"
        app:layout_constraintStart_toEndOf="@+id/name" />

    <TextView
        android:id="@+id/text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="8dp"
        android:text="text"
        android:textColor="@color/font_color_black"
        android:textSize="12sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/name"
        app:layout_constraintTop_toBottomOf="@+id/name" />

    <View
        android:id="@+id/line"
        android:layout_width="match_parent"
        android:layout_height="0.3dp"
        android:layout_marginTop="8dp"
        android:background="@color/background_border"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/chatListCardView" />

</androidx.constraintlayout.widget.ConstraintLayout>

values

使用する定数ファイルです

colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- フォントの色 黒 -->
    <color name="font_color_black">#5E5E5E</color>
    <!-- フォント オレンジ -->
    <color name="font_color_orange">#FF9900</color>
    <!-- background body -->
    <color name="background_light_gray">#EBEBEB</color>
    <!-- background header, footer -->
    <color name="background_dark_gray">#E5E5E5</color>
    <!-- background 区切り線 -->
    <color name="background_border">#838383</color>
    <!-- background 透過 -->
    <color name="background_transparent">#00E5E5E5</color>
</resources>

strings.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- 定数管理ファイル -->
<resources>
    <!-- アプリ名 -->
    <string name="app_name">Chat</string>
    <!-- チャット一覧画面 -->
    <string name="chat_list_subject_label">CHATS</string>
    <string name="chat_list_delete_button_color">#FF9900</string>
    <string name="chat_list_delete_button_label">DELETE</string>
    <string name="delete_dialog_message">このチャット履歴を削除しても\nよろしいでしょうか?</string>
    <string name="delete_dialog_list_tag">chatList</string>
</resources>


styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorAccent">@color/font_color_orange</item>
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>
</resources>


以上のコードで冒頭のサンプルの動きが再現できると思います。
こちらにソースも上がっていますので宜しければご確認ください。
https://github.com/yuta-matsumoto/chat

最後に

ハンズオン系の記事を初めて書きましたが、どこまで説明すべきか非常に戸惑いますね。。
もしどなたかの助けになれましたらとても嬉しいです!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Android] Waiting For Debuggerが終わらない時の打開策?

困って調べたのでメモ代わりに載せます

何のこと?

デバッグ中に起こる

Waiting For Debugger
Application is waiting for the debugger to attach.

このダイアログがいつまでも消えない問題。

解決方法

エミュレーター側で、

  1. Settings(設定) -> About emulated device(エミュレートされたデバイスについて) -> Build number(ビルド番号) を7回タップ →Developer options(開発者向けオプション)が有効になる
  2. Settings(設定) -> System(システム) -> Advanced(詳細設定) -> Developer options(開発者向けオプション) -> Select debug app(デバッグアプリを選択)を開き、自分のアプリを選択する

実機でも一緒だと思います。

調査時の環境:Android Studio 4.0 / Android 10

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MacでゼロからのFlutter環境構築

ゼロからFlutterの開発環境を構築するには以下の3つの手順が必要です。

  1. Flutterを導入する
  2. Xcodeを設定する
  3. Android Studioを設定する

Flutterを導入する

Flutterのインストール

Flutter公式からインストーラーをダウンロードします。
ダウンロードしたzipを解答して、flutterフォルダを任意の場所に置いてください。
私はアプリケーション直下に配置しました。

コマンドの有効化

  • flutterフォルダの中にあるflutter_console.batを実行します。 これでFlutter Consoleからflutterコマンドが使えるようになります。

Pathを通す

~/.bashrcまたは~/.bash_profileに以下を記述する。

$ export PATH=$PATH:/Applications/flutter/bin

Xcodeを設定する

Xcodeのインストール

App StoreでXcodeを検索してインストールします。
Xcodeのインストールにはかなり時間がかかります。時間の余裕がある時にインストールをしておくのをおすすめします。

Xcodeの設定を変更する

このコマンドを実装する。これでXcodeが使用できるようになる。

$ sudo xcode-select —switch /Applications/Xcode.app/Contents/Developer

ライセンスを表示して同意する。
コマンドから行ってもいいし、Xcodeを起動するでもOK。

$ sudo xcodebuild -license

Android Studio

Android Studioのインストール

App StoreでAndroid Studioを検索してインストールします。
こちらもなかなかお時間がかかりましたね。。

Flutter Pluginのインストール

メニュー>Android Studio>Preference...を選択する。
スクリーンショット 2020-06-26 0.55.05.png

横のメニューからPluginを選択。Flutterを検索してインストールする。
※画像はインストール済み

Android SDK toolsを設定する

Android SDK toolsのパケージ名がAndroid-SDK command line toolsに変わっていて、flutterからAndroid SDKをみにいくのに失敗するようになっていました。
なのでこちらを設定します。

先ほどと同様にメニュー>Android Studio>Preference...を選択します。
横のメニューのAndroid SDKを選択した、SDK Toolsの一覧をみます。

こちらしたの方にあるHide Obsolete Packagesのチェックを外すとAndroid SDK toolsが一覧に出てくるのでインストールします。

動作確認

ターミナルで以下を実行。こんな感じで返ってくれば完了です。
No devices availableこれはシミュレーターを起動していない時に出るので、実際作業するときはお忘れなく。

$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.12.13+hotfix.9, on Mac OS X 10.15.4 19E266, locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 11.5)
[✓] Android Studio (version 3.6)
[!] Connected device
    ! No devices available

! Doctor found issues in 1 category.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Android + kotlin + ViewPager2 でカレンダーの横スクロールを実現する

概要

今回は前回作った6月のカレンダーをスクロールして、7,8月のカレンダーも見れるようにしたいと思います。

技術テーマ

  • ViewPager2

横スクロールにはViewPagerは避けては通れないのでそちらを使って実装していこうと思います。

手順

Fragmentの作成

ViewPagerではスクロールすることでfragmentが切り替わるというものなので、今までActivityしか使ってなかったのですが、メインの処理をFragmentに移行したいと思います。

fragment_calendar.xml
<layout 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">

    <data>

        <variable
            name="date"
            type="String[]" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <!--縦分割のガイドライン-->
        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/youbi"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="0.1" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/line_1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="0.25" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/line_2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="0.40" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/line_3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="0.55" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/line_4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="0.70" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/line_5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="0.85" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/line_6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="1" />

        <!--横分割のガイドライン-->
        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/row1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="0.14" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/row2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="0.28" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/row3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="0.42" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/row4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="0.56" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/row5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="0.70" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/row6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="0.84" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/row7"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="1" />


        <TextView
            android:id="@+id/sunday"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style_red"
            android:gravity="center_horizontal|center_vertical"
            android:text="Sun"
            app:layout_constraintBottom_toBottomOf="@id/youbi"
            app:layout_constraintEnd_toEndOf="@id/row1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />


        <TextView
            android:id="@+id/monday"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="Mon"
            app:layout_constraintBottom_toBottomOf="@id/youbi"
            app:layout_constraintEnd_toEndOf="@id/row2"
            app:layout_constraintStart_toEndOf="@+id/row1"
            app:layout_constraintTop_toTopOf="@+id/sunday" />

        <TextView
            android:id="@+id/tuesday"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="Tue"
            app:layout_constraintBottom_toBottomOf="@id/youbi"
            app:layout_constraintEnd_toEndOf="@id/row3"
            app:layout_constraintStart_toEndOf="@+id/row2"
            app:layout_constraintTop_toTopOf="@+id/sunday" />

        <TextView
            android:id="@+id/wednesday"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="Wed"
            app:layout_constraintBottom_toBottomOf="@id/youbi"
            app:layout_constraintEnd_toEndOf="@id/row4"
            app:layout_constraintStart_toEndOf="@+id/row3"
            app:layout_constraintTop_toTopOf="@+id/sunday" />

        <TextView
            android:id="@+id/thursday"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="Thu"
            app:layout_constraintBottom_toBottomOf="@id/youbi"
            app:layout_constraintEnd_toEndOf="@id/row5"
            app:layout_constraintStart_toEndOf="@+id/row4"
            app:layout_constraintTop_toTopOf="@+id/sunday" />

        <TextView
            android:id="@+id/friday"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="Fri"
            app:layout_constraintBottom_toBottomOf="@id/youbi"
            app:layout_constraintEnd_toEndOf="@id/row6"
            app:layout_constraintStart_toEndOf="@+id/row5"
            app:layout_constraintTop_toTopOf="@+id/sunday" />

        <TextView
            android:id="@+id/saturday"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style_blue"
            android:gravity="center_horizontal|center_vertical"
            android:text="Sat"
            app:layout_constraintBottom_toBottomOf="@id/youbi"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@id/row6"
            app:layout_constraintTop_toTopOf="@+id/sunday" />


        <TextView
            android:id="@+id/cell_1"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style_red"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[0]}"
            app:layout_constraintBottom_toBottomOf="@id/line_1"
            app:layout_constraintEnd_toEndOf="@id/row1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@id/youbi" />


        <TextView
            android:id="@+id/cell_2"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[1]}"
            app:layout_constraintBottom_toBottomOf="@id/line_1"
            app:layout_constraintEnd_toEndOf="@id/row2"
            app:layout_constraintStart_toEndOf="@+id/row1"
            app:layout_constraintTop_toTopOf="@id/youbi" />

        <TextView
            android:id="@+id/cell_3"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[2]}"
            app:layout_constraintBottom_toBottomOf="@id/line_1"
            app:layout_constraintEnd_toEndOf="@id/row3"
            app:layout_constraintStart_toEndOf="@+id/row2"
            app:layout_constraintTop_toTopOf="@id/youbi" />

        <TextView
            android:id="@+id/cell_4"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[3]}"
            app:layout_constraintBottom_toBottomOf="@id/line_1"
            app:layout_constraintEnd_toEndOf="@id/row4"
            app:layout_constraintStart_toEndOf="@+id/row3"
            app:layout_constraintTop_toTopOf="@id/youbi" />

        <TextView
            android:id="@+id/cell_5"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[4]}"
            app:layout_constraintBottom_toBottomOf="@id/line_1"
            app:layout_constraintEnd_toEndOf="@id/row5"
            app:layout_constraintStart_toEndOf="@+id/row4"
            app:layout_constraintTop_toTopOf="@id/youbi" />

        <TextView
            android:id="@+id/cell_6"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[5]}"
            app:layout_constraintBottom_toBottomOf="@id/line_1"
            app:layout_constraintEnd_toEndOf="@id/row6"
            app:layout_constraintStart_toEndOf="@+id/row5"
            app:layout_constraintTop_toTopOf="@id/youbi" />

        <TextView
            android:id="@+id/cell_7"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style_blue"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[6]}"
            app:layout_constraintBottom_toBottomOf="@id/line_1"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@id/row6"
            app:layout_constraintTop_toTopOf="@id/youbi" />

        <TextView
            android:id="@+id/cell_21"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style_red"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[7]}"
            app:layout_constraintBottom_toBottomOf="@id/line_2"
            app:layout_constraintEnd_toEndOf="@id/row1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@id/line_1" />


        <TextView
            android:id="@+id/cell_22"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[8]}"
            app:layout_constraintBottom_toBottomOf="@id/line_2"
            app:layout_constraintEnd_toEndOf="@id/row2"
            app:layout_constraintStart_toEndOf="@+id/row1"
            app:layout_constraintTop_toTopOf="@id/line_1" />

        <TextView
            android:id="@+id/cell_23"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[9]}"
            app:layout_constraintBottom_toBottomOf="@id/line_2"
            app:layout_constraintEnd_toEndOf="@id/row3"
            app:layout_constraintStart_toEndOf="@+id/row2"
            app:layout_constraintTop_toTopOf="@id/line_1" />

        <TextView
            android:id="@+id/cell_24"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[10]}"
            app:layout_constraintBottom_toBottomOf="@id/line_2"
            app:layout_constraintEnd_toEndOf="@id/row4"
            app:layout_constraintStart_toEndOf="@+id/row3"
            app:layout_constraintTop_toTopOf="@id/line_1" />

        <TextView
            android:id="@+id/cell_25"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[11]}"
            app:layout_constraintBottom_toBottomOf="@id/line_2"
            app:layout_constraintEnd_toEndOf="@id/row5"
            app:layout_constraintStart_toEndOf="@+id/row4"
            app:layout_constraintTop_toTopOf="@id/line_1" />

        <TextView
            android:id="@+id/cell_26"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[12]}"
            app:layout_constraintBottom_toBottomOf="@id/line_2"
            app:layout_constraintEnd_toEndOf="@id/row6"
            app:layout_constraintStart_toEndOf="@+id/row5"
            app:layout_constraintTop_toTopOf="@id/line_1" />

        <TextView
            android:id="@+id/cell_27"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style_blue"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[13]}"
            app:layout_constraintBottom_toBottomOf="@id/line_2"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@id/row6"
            app:layout_constraintTop_toTopOf="@id/line_1" />

        <TextView
            android:id="@+id/cell_31"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style_red"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[14]}"
            app:layout_constraintBottom_toBottomOf="@id/line_3"
            app:layout_constraintEnd_toEndOf="@id/row1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@id/line_2" />


        <TextView
            android:id="@+id/cell_32"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[15]}"
            app:layout_constraintBottom_toBottomOf="@id/line_3"
            app:layout_constraintEnd_toEndOf="@id/row2"
            app:layout_constraintStart_toEndOf="@+id/row1"
            app:layout_constraintTop_toTopOf="@id/line_2" />

        <TextView
            android:id="@+id/cell_33"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[16]}"
            app:layout_constraintBottom_toBottomOf="@id/line_3"
            app:layout_constraintEnd_toEndOf="@id/row3"
            app:layout_constraintStart_toEndOf="@+id/row2"
            app:layout_constraintTop_toTopOf="@id/line_2" />

        <TextView
            android:id="@+id/cell_34"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[17]}"
            app:layout_constraintBottom_toBottomOf="@id/line_3"
            app:layout_constraintEnd_toEndOf="@id/row4"
            app:layout_constraintStart_toEndOf="@+id/row3"
            app:layout_constraintTop_toTopOf="@id/line_2" />

        <TextView
            android:id="@+id/cell_35"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[18]}"
            app:layout_constraintBottom_toBottomOf="@id/line_3"
            app:layout_constraintEnd_toEndOf="@id/row5"
            app:layout_constraintStart_toEndOf="@+id/row4"
            app:layout_constraintTop_toTopOf="@id/line_2" />

        <TextView
            android:id="@+id/cell_36"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[19]}"
            app:layout_constraintBottom_toBottomOf="@id/line_3"
            app:layout_constraintEnd_toEndOf="@id/row6"
            app:layout_constraintStart_toEndOf="@+id/row5"
            app:layout_constraintTop_toTopOf="@id/line_2" />

        <TextView
            android:id="@+id/cell_37"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style_blue"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[20]}"
            app:layout_constraintBottom_toBottomOf="@id/line_3"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@id/row6"
            app:layout_constraintTop_toTopOf="@id/line_2" />

        <TextView
            android:id="@+id/cell_41"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style_red"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[21]}"
            app:layout_constraintBottom_toBottomOf="@id/line_4"
            app:layout_constraintEnd_toEndOf="@id/row1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@id/line_3" />

        <TextView
            android:id="@+id/cell_42"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[22]}"
            app:layout_constraintBottom_toBottomOf="@id/line_4"
            app:layout_constraintEnd_toEndOf="@id/row2"
            app:layout_constraintStart_toEndOf="@+id/row1"
            app:layout_constraintTop_toTopOf="@id/line_3" />

        <TextView
            android:id="@+id/cell_43"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[23]}"
            app:layout_constraintBottom_toBottomOf="@id/line_4"
            app:layout_constraintEnd_toEndOf="@id/row3"
            app:layout_constraintStart_toEndOf="@+id/row2"
            app:layout_constraintTop_toTopOf="@id/line_3" />

        <TextView
            android:id="@+id/cell_44"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[24]}"
            app:layout_constraintBottom_toBottomOf="@id/line_4"
            app:layout_constraintEnd_toEndOf="@id/row4"
            app:layout_constraintStart_toEndOf="@+id/row3"
            app:layout_constraintTop_toTopOf="@id/line_3" />

        <TextView
            android:id="@+id/cell_45"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[25]}"
            app:layout_constraintBottom_toBottomOf="@id/line_4"
            app:layout_constraintEnd_toEndOf="@id/row5"
            app:layout_constraintStart_toEndOf="@+id/row4"
            app:layout_constraintTop_toTopOf="@id/line_3" />

        <TextView
            android:id="@+id/cell_46"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[26]}"
            app:layout_constraintBottom_toBottomOf="@id/line_4"
            app:layout_constraintEnd_toEndOf="@id/row6"
            app:layout_constraintStart_toEndOf="@+id/row5"
            app:layout_constraintTop_toTopOf="@id/line_3" />

        <TextView
            android:id="@+id/cell_47"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style_blue"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[27]}"
            app:layout_constraintBottom_toBottomOf="@id/line_4"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@id/row6"
            app:layout_constraintTop_toTopOf="@id/line_3" />

        <TextView
            android:id="@+id/cell_51"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style_red"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[28]}"
            app:layout_constraintBottom_toBottomOf="@id/line_5"
            app:layout_constraintEnd_toEndOf="@id/row1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@id/line_4" />

        <TextView
            android:id="@+id/cell_52"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[29]}"
            app:layout_constraintBottom_toBottomOf="@id/line_5"
            app:layout_constraintEnd_toEndOf="@id/row2"
            app:layout_constraintStart_toEndOf="@+id/row1"
            app:layout_constraintTop_toTopOf="@id/line_4" />

        <TextView
            android:id="@+id/cell_53"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[30]}"
            app:layout_constraintBottom_toBottomOf="@id/line_5"
            app:layout_constraintEnd_toEndOf="@id/row3"
            app:layout_constraintStart_toEndOf="@+id/row2"
            app:layout_constraintTop_toTopOf="@id/line_4" />

        <TextView
            android:id="@+id/cell_54"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[31]}"
            app:layout_constraintBottom_toBottomOf="@id/line_5"
            app:layout_constraintEnd_toEndOf="@id/row4"
            app:layout_constraintStart_toEndOf="@+id/row3"
            app:layout_constraintTop_toTopOf="@id/line_4" />

        <TextView
            android:id="@+id/cell_55"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[32]}"
            app:layout_constraintBottom_toBottomOf="@id/line_5"
            app:layout_constraintEnd_toEndOf="@id/row5"
            app:layout_constraintStart_toEndOf="@+id/row4"
            app:layout_constraintTop_toTopOf="@id/line_4" />

        <TextView
            android:id="@+id/cell_56"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[33]}"
            app:layout_constraintBottom_toBottomOf="@id/line_5"
            app:layout_constraintEnd_toEndOf="@id/row6"
            app:layout_constraintStart_toEndOf="@+id/row5"
            app:layout_constraintTop_toTopOf="@id/line_4" />

        <TextView
            android:id="@+id/cell_57"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style_blue"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[34]}"
            app:layout_constraintBottom_toBottomOf="@id/line_5"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@id/row6"
            app:layout_constraintTop_toTopOf="@id/line_4" />

        <TextView
            android:id="@+id/cell_61"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style_red"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[35]}"
            app:layout_constraintBottom_toBottomOf="@id/line_6"
            app:layout_constraintEnd_toEndOf="@id/row1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@id/line_5" />

        <TextView
            android:id="@+id/cell_62"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[36]}"
            app:layout_constraintBottom_toBottomOf="@id/line_6"
            app:layout_constraintEnd_toEndOf="@id/row2"
            app:layout_constraintStart_toEndOf="@+id/row1"
            app:layout_constraintTop_toTopOf="@id/line_5" />

        <TextView
            android:id="@+id/cell_63"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[37]}"
            app:layout_constraintBottom_toBottomOf="@id/line_6"
            app:layout_constraintEnd_toEndOf="@id/row3"
            app:layout_constraintStart_toEndOf="@+id/row2"
            app:layout_constraintTop_toTopOf="@id/line_5" />

        <TextView
            android:id="@+id/cell_64"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[38]}"
            app:layout_constraintBottom_toBottomOf="@id/line_6"
            app:layout_constraintEnd_toEndOf="@id/row4"
            app:layout_constraintStart_toEndOf="@+id/row3"
            app:layout_constraintTop_toTopOf="@id/line_5" />

        <TextView
            android:id="@+id/cell_65"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[39]}"
            app:layout_constraintBottom_toBottomOf="@id/line_6"
            app:layout_constraintEnd_toEndOf="@id/row5"
            app:layout_constraintStart_toEndOf="@+id/row4"
            app:layout_constraintTop_toTopOf="@id/line_5" />

        <TextView
            android:id="@+id/cell_66"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[40]}"
            app:layout_constraintBottom_toBottomOf="@id/line_6"
            app:layout_constraintEnd_toEndOf="@id/row6"
            app:layout_constraintStart_toEndOf="@+id/row5"
            app:layout_constraintTop_toTopOf="@id/line_5" />

        <TextView
            android:id="@+id/cell_67"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/flame_style_blue"
            android:gravity="center_horizontal|center_vertical"
            android:text="@{date[41]}"
            app:layout_constraintBottom_toBottomOf="@id/line_6"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@id/row6"
            app:layout_constraintTop_toTopOf="@id/line_5" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

CalendarFragment.kt
package com.example.myfavoritecontentsmanage

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.example.myfavoritecontentsmanage.databinding.FragmentCalendarBinding
import java.util.*

class CalendarFragment() : Fragment() {
    private lateinit var binding: FragmentCalendarBinding
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentCalendarBinding.inflate(inflater, container, false)
        inflater.inflate(R.layout.fragment_calendar, container, false)
        val calendar = Calendar.getInstance()
        val year = 2019
        val month = 6
        val minDay = 1
        calendar.set(year, month - 1, 1)
        val maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH)
        val blankDays = calendar.get(Calendar.DAY_OF_WEEK)

        val dayArray: MutableList<String> = mutableListOf()
        for (i in minDay until blankDays) {
            dayArray.add("")
        }
        for (i in minDay..maxDay) {
            dayArray.add(i.toString())
        }
        binding.date = dayArray.toTypedArray()

        return binding.root
    }
}

基本的にただ移行するだけなのでそこまで苦戦することはありません。

ViewPager2の利用

前提
ViewPager2を使うためにはgradleに下記の記述を追加します。

    implementation "androidx.viewpager2:viewpager2:1.0.0"

まず、アクティビティのレイアウトファイルでviewPagerを定義します。

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />


    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

そしてMainActivityでadapterを呼び出し、連結します。

MainActivity.kt
package com.example.myfavoritecontentsmanage

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.example.myfavoritecontentsmanage.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        super.onCreate(savedInstanceState)
//        setContentView(R.layout.activity_main)

        val pager = ScreenSlidePagerAdapter(this)
        binding.pager.adapter = pager

    }

    private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
        override fun getItemCount(): Int = 3

        override fun createFragment(position: Int): Fragment = CalendarFragment(position)
    }
}

実行結果がこちら!

mojikyo45_640-2.gif

ちょっと月の表示が無いのでわかりにくいかもしれないのですが、ちゃんと切り替わっている様子が伝わるかと!!!

今回は3の制限が付いていて、しかも5月など過去の月が表示できないのでその辺りを調整しようと思います!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む