全方向への同時スクロールの実装

はじめに



良い一日! 私は最近プログラミングを始めましたが、あまり経験がないため、特にこのトピックに関する資料が非常に少ないため、厳密に判断しないでください。 この記事では、ターンベースの2D戦略を作成するときに抱えていた問題に対するソリューションを共有したいと思います。 戦略については、通常は競技場の存在です。 しかし、ユーザーの携帯電話が小さく、競技場全体が画面に収まらない場合はどうでしょうか? 私はまだ1か月も前にこの質問をしましたが、まだ準備ができていませんでした。 最初に、ScrollViewとHorizo​​ntalScrollViewで通常どおりフィールドをラップすることにしました。 そして、ここから問題が始まります。 一度に一方向にしかスクロールできないため、特にゲームでは非常に不便です。 この問題の解決に興味がある場合は、catにようこそ。



整理



まず、私たちがすでに持っているものについて考え、すぐに私たち自身のものを発明しようとしないでください。 Googleのドキュメントでしばらくの間ScrollViewクラスの情報を探した後、すべてがそれほど悪いわけではないことが明らかになりました。 onInterceptTouchEvent(MotionEvent ev)メソッドを見てください。 タッチのインターセプトを決定するために呼び出されます-これが必要です。 フィールド要素をクリックする場合を除き、彼がすべての動きをキャッチすることを確認する必要があります。 これは次のようなものです。



垂直スクロールクラス
public final class MultiScrollView extends ScrollView { //   private int origX, origY; //     ,  60 px,    private final float THRESHOLD = 60; public MultiScrollView(Context context) { super(context); } public MultiScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public MultiScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean canScrollHorizontally(int direction) { return true; } @Override public boolean canScrollVertically(int direction) { return true; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { origX = (int) ev.getX(); origY = (int) ev.getY(); } else if (ev.getAction() == MotionEvent.ACTION_MOVE) { float deltaX = Math.abs(ev.getX() - origX); float deltaY = Math.abs(ev.getY() - origY); return deltaX >= THRESHOLD || deltaY >= THRESHOLD; } return false; } }
      
      







ご覧のとおり、タッチは、指の座標の変化が60ピクセルを超える場合にのみインターセプトされます。 また、このクラスでは、canScrollHorizo​​ntallyメソッドをオーバーライドして、常にtrueを返すようにする必要があります。



また、独自の水平スクロールクラスを作成する必要があります。



水平スクロールクラス
 public final class MyHorizontalScrollView extends HorizontalScrollView { public MyHorizontalScrollView(Context context) { super(context); } public MyHorizontalScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public MyHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return false; } @Override public boolean canScrollHorizontally(int direction) { return false; } @Override public boolean onTouchEvent(MotionEvent ev) { return false; } }
      
      







ここでは、タッチに反応することを禁止します。



確認する



次に、その仕組みを確認する必要があります。 マークアップを作成します。



アクティビティマークアップ-activity_main.xml
 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <example.multiscroll.MultiScrollView android:id="@+id/field_y" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="@color/color_black" android:fadingEdgeLength="0dp" android:focusable="true" android:isScrollContainer="true" android:overScrollMode="never" android:requiresFadingEdge="none" android:scrollbars="none" android:splitMotionEvents="true" tools:context="example.multiscroll.MainActivity"> <example.multiscroll.MyHorizontalScrollView android:id="@+id/field_x" android:layout_width="match_parent" android:layout_height="wrap_content" android:fadingEdgeLength="0dp" android:focusable="false" android:isScrollContainer="true" android:overScrollMode="never" android:requiresFadingEdge="none" android:scrollbars="none" android:splitMotionEvents="true"> <TableLayout android:id="@+id/table" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/color_white" android:orientation="vertical" android:paddingBottom="70dp" android:paddingEnd="140dp" android:paddingLeft="140dp" android:paddingRight="140dp" android:paddingStart="140dp" android:paddingTop="70dp" /> </example.multiscroll.MyHorizontalScrollView> </example.multiscroll.MultiScrollView> </RelativeLayout>
      
      







フィールド要素マークアップ-sq.xml
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="100dp" android:layout_height="100dp" android:layout_margin="5dp"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>
      
      







ここで、すべてのマークアップをアクティビティに接続します。 私はすぐに、フィールドの要素が動的な要素を作成するという事実に注目します。 任意の数の行と列を指定できます。 フィールド要素には別のファイルが使用されます(私のプロジェクトでは、画像とその上に2つのテキストフィールドが含まれていますが、たとえば不要です)。



アクティビティコード-​​MainActivity.java
 public class MainActivity extends Activity { private ScrollView scrollY; private GestureDetector gestureDetectorY; private RelativeLayout[][] sqContent; private int sizeI = 10; private int sizeJ = 20; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sqContent = new RelativeLayout[sizeI][sizeJ]; scrollY = (MultiScrollView) findViewById(R.id.field_y); gestureDetectorY = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { scrollX.smoothScrollBy((int) distanceX, 0); scrollY.smoothScrollBy(0, (int) (distanceY)); return true; } }); scrollY.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { gestureDetectorY.onTouchEvent(event); return true; } }); TableLayout table = (TableLayout) findViewById(R.id.table); TableRow row[] = new TableRow[sizeJ]; TableRow.LayoutParams paramsTableRow = new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT); paramsTableRow.setMargins(0, 50, 0, 50); paramsTableRow.weight = 1; for (int i = 0; i < sizeI; i++) { row[i] = new TableRow(this); row[i].setLayoutParams(paramsTableRow); row[i].setWeightSum(sizeJ); for (int j = 0; j < sizeJ; j++) { sqContent[i][j] = (RelativeLayout) getLayoutInflater().inflate(R.layout.sq, row[i], false); sqContent[i][j].setBackgroundResource(R.color.color_sq_action); sqContent[i][j].setOnClickListener(getOnClickListener()); row[i].addView(sqContent[i][j], j); } table.addView(row[i], i); } } private View.OnClickListener getOnClickListener() { return new View.OnClickListener() { @Override public void onClick(View v) { v.setBackgroundResource(R.color.color_black); } }; } }
      
      







たとえば、フィールドのサイズを20〜10にしました。ここでは、GestureDetectorクラスのオブジェクトに特に注意を払う必要があります。 ジェスチャーを識別するために必要です。 水平および垂直スクロール用のタッチハンドラーで、イベントを渡します。 これにより、X軸とY軸に沿ってスクロールが発生し、また、フィールド要素をクリックすることの利便性を確認するために、色を変更するリスナーをその要素に掛けました。 押さないで、少し(<= 60 px)押したままにしても、色が変わります。 したがって、押すことの利便性に問題はありません。 私の決定を十分詳細に説明し、それが明らかになったことを願っています。



このプロジェクトのソースはこちらからダウンロードできます。



All Articles