スクロールとスワイプの共存

　AndroidStudioでGoogleカレンダーを模したアプリを作成していたところ、問題発生。

 **スワイプで前後の日週月に移動させたいが、日のみ縦スクロールが優先されてスワイプできない**

 　検索する限り様々対策されている方はいるようだが、自分のケースにあった解決法が見当たらなかったため、ChatGPTと相談しながら原因特定→問題解決を図った。が、なかなかいい解決方法が出てこないので、最終的には自分がこれ、と思った解決方法が当たった。

# 問題発生時の状況
　メイン画面（MainActivity）で上部タブにより、月・週・日の表示が切り替え可能。日のみ縦にスクロールして24時間分を表示させる。（GoogleCalendarの上にタブがあると思ってください）
　横スワイプでは前後の月・週・日付に移動させる（GestureDetectorを使用）が、日のみスワイプできない。

# 原因
　ScrollViewが優先されてGestureDetectorが効かなくなっている。

# 改善策
　スワイプ方向に応じてScrollViewを無効にする必要があるが、最初はこれをMainActivity.javaで実施しようとしていたが、うまくいかない。そこで、日の画面だけはMainActivity.javaでGestureDetectorのタッチリスナーを無効にし、日画面作成時にactivity_mainのコンテキストを引き継いだうえでGestureDetectorを実装。また、ScrollViewのタッチリスナーで横スワイプを無効に設定。

# コード抜粋
　文章では分かりづらいため、コードの抜粋を以下に示す。
 ```Java:MainActivity.java
public class MainActivity extends AppCompatActivity {
    @Override
  protected void onCreate(Bundle savedInstanceState) {
    
    // GestureDetectorの設定
    gestureDetector = new GestureDetector(this, new GestureListener());

    // タブのクリックリスナー設定
    dateTypeTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
      @Override
      public void onTabSelected(@NonNull TabLayout.Tab tab) {
        // タブが選択されたときに、タブの位置に応じて画面を表示
        int tabPosition = tab.getPosition();

        // タブのテキストを更新
        updateTextViewBasedOnDate(showingDate);

        // タブの位置に応じて適切なフラグメントを作成
        displayFragmentForTab(tabPosition);

//        タブがDayタブ以外の場合、スワイプジェスチャーを有効にする（DayのスワイプはDayFragmentで設定）
        if (tabPosition != 2) { // Dayタブ以外が選択された場合
          findViewById(R.id.toDoDisplay).setOnTouchListener((v, event) -> {
            gestureDetector.onTouchEvent(event);
            return true;
          });
        } else {
          findViewById(R.id.toDoDisplay).setOnTouchListener(null);
        }
      }
      @Override
      public void onTabUnselected(@NonNull TabLayout.Tab tab) {
        // タブが非選択になったときの処理（必要なら追加）
      }

      @Override
      public void onTabReselected(@NonNull TabLayout.Tab tab) {
        // タブが再選択されたときの処理（必要なら追加）
      }
    });
  }

  public void displayFragmentForTab(int tabPosition) {
    Fragment fragment;

    switch (tabPosition) {
      case 0:
        fragment = MonthFragment.newInstance(showingDate);
        break;
      case 1:
        fragment = WeekFragment.newInstance(showingDate);
        break;
      case 2:
        fragment = DayFragment.newInstance(showingDate);
        break;
      default:
        fragment = DayFragment.newInstance(showingDate); // デフォルトのフラグメント
        break;
    }

    // フラグメントを表示
    getSupportFragmentManager().beginTransaction()
        .replace(R.id.toDoDisplay, fragment)
        .commit();
  }
}
 ```

 ```Java:DayFragment.xml
public class DayFragment extends Fragment {
  private MainActivity mainActivity;

  private static final String ARG_DATE = "showingDate";
  private Date showingDate;

  private TabLayout dateTypeTabLayout;
  private GestureDetector gestureDetector;

  public DayFragment() {
  }

  public static DayFragment newInstance(Date showingDate) {
    DayFragment fragment = new DayFragment();
    Bundle args = new Bundle();
    args.putSerializable(ARG_DATE, showingDate);
    fragment.setArguments(args);
    return fragment;
  }

  @Override
  public void onAttach(Context context) {
    super.onAttach(context);
    if (context instanceof MainActivity) {
      mainActivity = (MainActivity) context; // contextをMainActivityにキャスト
    } else {
      throw new RuntimeException(context.toString()
          + " must be an instance of MainActivity");
    }
  }

  @Override
  public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
      showingDate = (Date) getArguments().getSerializable(ARG_DATE);
    }
  }

  @Override
  public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_day, container, false);

    gestureDetector = new GestureDetector(getContext(), mainActivity.new GestureListener());
    ScrollView scrollView = rootView.findViewById(R.id.dayScrollView);

    // ScrollView に OnTouchListener を設定
    scrollView.setOnTouchListener((v, event) -> {
      if (gestureDetector.onTouchEvent(event)) {
        // 横スワイプを検出した場合、ScrollView のスクロールを無効にする
        return true;
      } else {
        // 縦スワイプの場合、ScrollView のデフォルトのスクロールを許可する
        return v.onTouchEvent(event);
      }
    });

    return rootView;
  }
}
 ```