ViewPager modifizieren

N

no1Ltan

Fortgeschrittenes Mitglied
7
Hallo,

ich habe auf GitHub ein Projekt runtergeladen, in dem es sowohl einen horizontalen als auch einen vertikalen VP gibt.
JayaprakashR-Zealot/SnapchatDashboard
Die App startet auf dem zentralen Fragment, von dem aus man in alle Richtungen swipen kann, um die jeweiligen Fragmente aufzurufen.

Mich interessiert, ob es möglich ist, dem vertikalen Swipen andere Funktionalitäten zuzuweisen.
Z.B. Toasts.

Horizontales Swipen soll weiterhin wechseln der Fragmente genutzt werden können.

Ich hatte mich bereits innerhalb der VerticalPager.java ausgetobt, aber ich schaffe es einfach nicht,
das vertikale Swipen (welches die Fragmente ändert), zu unterbinden.
Geht mein Vorhaben überhaupt?

Hier ist übrigens meine aktuelle Version des VerticalPagers, aber wie gesagt, es funktioniert nicht:

Edit by MOD : Source entfernt, da kein komplettes Eigenwerk des TE, Link dazu siehe oben .

Danke für jede Hilfe!
 
Zuletzt bearbeitet von einem Moderator:
Hallo
Mit dem Viewpager wirst du nicht viel Erfolg haben. Der ist für das starten von Fragments über Wisch Gesten gedacht , aber nicht um andere Aktionen über Gesten auszuführen.

Ich denke für dein Vorhaben ist ein GestureDetecto, OnGestureListener besser geeignet als der Viewpager.

Ps. Habe mir deinen Code nicht angesehen. Da es für mich keinen Sinn macht dafür ein Viewpager zu benutzen.
 
  • Danke
Reaktionen: no1Ltan
Hallo und danke für deine ehrlichen Worte.

Ich habe viel rumexperiementiert und Fortschritte gemacht.
Der Viewpager funktioniert und es werden gleichzeitig TouchEvents registriert.
(Das ging vorher nie, weil der VP dies blockierte.)

Das ist die GestureListener-Klasse:
Code:
import android.view.GestureDetector;
import android.view.MotionEvent;

class GestureListener extends GestureDetector.SimpleOnGestureListener
{
    static String currentGestureDetected;
    
    @Override
    public boolean onSingleTapUp(MotionEvent motionEvent)
    {
        currentGestureDetected = motionEvent.toString();
        return true;
    }
    @Override
    public void onShowPress(MotionEvent motionEvent)
    {
        currentGestureDetected = motionEvent.toString();
    }
    @Override
    public void onLongPress(MotionEvent motionEvent)
    {
        currentGestureDetected = motionEvent.toString();
    }
    @Override
    public boolean onScroll(MotionEvent motionEvent1, MotionEvent motionEvent2, float distanceX, float distanceY)
    {
        currentGestureDetected = motionEvent1.toString()+ "  "+motionEvent2.toString();
        return true;
    }
    @Override
    public boolean onDown(MotionEvent motionEvent)
    {
        currentGestureDetected = motionEvent.toString();
        return true;
    }
    @Override
    public boolean onFling(MotionEvent motionEvent1, MotionEvent motionEvent2, float velocityX, float velocityY)
    {
        currentGestureDetected = motionEvent1.toString()+ "  "+motionEvent2.toString();
        return true;
    }
}

Fragment1:
Code:
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

public class Fragment1 extends Fragment
{
    GestureDetector gestureDetector;
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
    {
        View fragment1 = inflater.inflate(R.layout.fragment1, container, false); // Link view and layout
        gestureDetector = new GestureDetector(getActivity(), new GestureListener());
        fragment1.setOnTouchListener(new View.OnTouchListener()
        {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent)
            {
                boolean eventConsumed = gestureDetector.onTouchEvent(motionEvent);
                if (eventConsumed)
                {
                    Toast.makeText(getActivity(), "hello", Toast.LENGTH_SHORT).show();
                    return true;
                }
                else
                {
                    return false;
                }
            }
        });
        return fragment1;
    }
}

Fragment2:
Code:
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

public class Fragment2 extends Fragment
{
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
    {
        View fragment2 = inflater.inflate(R.layout.fragment2, container, false); // Link view and layout
        return fragment2;
    }
}

Mein Problem:
Ich würde gerne nur die y-Touches abfangen.
Von unten nach oben bzw. von oben nach unten.
Nur dann soll der Toast erscheinen.
Beim horizontalem Touch braucht kein Toast erscheinen, da dieser ja die Fragmente wechselt (VP).

Leider qualmt mir grad der Kopf, so dass ich einfach nicht weiterkomme.
(Musste sehr sehr viel im Code ändern.)

Ich vermute, dass die onScroll-Methode dafür geeignet wäre?

Danke und viele Grüße
 
Zuletzt bearbeitet:
  • Danke
Reaktionen: no1Ltan
Vielen Dank für die Links, das hat mir geholfen!

Ob der Listener wirklich in die Activity gehört, weiß ich nicht.
Auf jeden Fall funktioniert es, wenn er im Fragment ist.

Leider hab ich ein anderes Problem:
Der GestureDetector funktioniert nicht, wenn man auf eine View klickt, die mit einem OnClick-Listener verknüpft ist.
Wische ich nach oben, passiert nichts.
Ein Wischen nach unten interpretiert Android als Klick.

Ich habe recherchiert und herausgefunden, dass man den OnClickListener einfach durch den OnTouchListener ersetzen kann,
aber da müsste ich die komplette Struktur verändern.
Außerdem würde der Code viel viel länger werden als vorher.

Wie auch immer, hier ein Beispiel-Code (funktioniert einwandfrei):
Code:
import android.os.Bundle;
import android.os.SystemClock;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;

public class Fragment1 extends Fragment
{
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
    {
        View fragment1 = inflater.inflate(R.layout.fragment1, container, false); // Link view and layout

        fragment1.setOnTouchListener(new Gesten()
        {
            public boolean onClick()
            {
                Toast.makeText(getContext(),"Einfacher Klick",Toast.LENGTH_SHORT).show();
                return false;
            }
            public boolean onLongClick()
            {
                super.onLongClick();
                Toast.makeText(getContext(),"Langer Klick",Toast.LENGTH_SHORT).show();
                return false;
            }
            public boolean onSwipeTop()
            {
                Toast.makeText(getContext(), "Es wurde nach oben gewischt", Toast.LENGTH_SHORT).show();
                return false;
            }
            public boolean onSwipeBottom()
            {
                Toast.makeText(getActivity(), "Es wurde nach unten gewischt", Toast.LENGTH_SHORT).show();
                return false;
            }
        });
        return fragment1;
    }
}

Sobald sich Views innerhalb dieses Layouts befinden, die mit einem OnClick-Listener verbunden sind, gibt es Probleme.
Warum überwiegt fragment1 nicht?

Plan B wäre, eine separate View über alle anderen zu legen, und nur diese mit dem OnTouchListener zu verbinden.
Die View reagiert nur auf Wisch-Gesten nach oben und unten.
Die anderen Views hingegen sollen weiterhin mit OnClickListenern verbunden sein.

Hast du eine Idee, ob/wie sich das realisieren lässt bzw. ob es vllt. bessere Lösungen gibt?

Ich habe das hier versucht, aber die vordere View blockiert die hinterliegende komplett.
Mein Wunsch wäre es, dass die vordere die 2 Wischgesten (hoch/runter) aufnimmt während die hintere die Klicks abfängt.
Code:
<?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"
    tools:layout_editor_absoluteY="81dp">

    <TextView
        android:id="@+id/text_view_header"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#000000"
        android:gravity="center_horizontal"
        android:paddingTop="2dp"
        android:textColor="#ffffff"
        android:textSize="15sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHeight_default="percent"
        app:layout_constraintHeight_percent="0.10"
        app:layout_constraintHorizontal_bias="0.503"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/constraint_layout_text"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#1d34a7"
        android:clickable="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHeight_default="percent"
        app:layout_constraintHeight_percent="0.9"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="1"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintWidth_percent="1"
        android:focusable="true" />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/constraint_layout_foreground"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#E91E63"
        android:clickable="false"
        android:focusable="false"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHeight_default="percent"
        app:layout_constraintHeight_percent="0.9"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="1"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintWidth_percent="1" />

</androidx.constraintlayout.widget.ConstraintLayout>

Code:
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;

public class Fragment1 extends Fragment implements View.OnClickListener
{
    ConstraintLayout constraintLayoutText, constraintLayoutForeground;
    @Override public void onResume()
    {
        super.onResume();
        constraintLayoutText = getActivity().findViewById(R.id.constraint_layout_text); // Link variable to ID
        constraintLayoutForeground = getActivity().findViewById(R.id.constraint_layout_foreground); // Link variable to ID
        getActivity().findViewById(R.id.constraint_layout_text).setOnClickListener(this);

        constraintLayoutForeground.setOnTouchListener(new Gesten()
        {
            public boolean onSwipeTop()
            {
                Toast.makeText(getContext(), "Es wurde nach oben gewischt", Toast.LENGTH_SHORT).show();
                return false;
            }
            public boolean onSwipeBottom()
            {
                Toast.makeText(getActivity(), "Es wurde nach unten gewischt", Toast.LENGTH_SHORT).show();
                return false;
            }
        });
    }
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
    {
        View fragment1 = inflater.inflate(R.layout.fragment1, container, false); // Link view and layout
        return fragment1;
    }
    @Override
    public void onClick(View view)
    {
        if (view.getId() == R.id.constraint_layout_text)
        {
            Toast.makeText(getActivity(), "TextView wurde geklickt", Toast.LENGTH_SHORT).show();
        }
    }
}

Danke und viele Grüße
 
Hallo,

ich versuche mal mein Problem etwas besser zu erklären.
In diesem Beispiel habe ich nur einen OnClickListener verwendet.
Mir gefällt die Struktur, da ich nicht für jeden Button ein separaten OnClickListener verwende:
Code:
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;

public class Fragment1 extends Fragment implements View.OnClickListener
{
    ConstraintLayout constraintLayoutRed, constraintLayoutBlue;
    @Override public void onResume()
    {
        super.onResume();
        constraintLayoutBlue = getActivity().findViewById(R.id.constraint_layout_blue); // Link variable to ID
        constraintLayoutRed = getActivity().findViewById(R.id.constraint_layout_red); // Link variable to ID
        getActivity().findViewById(R.id.constraint_layout_red).setOnClickListener(this);
        getActivity().findViewById(R.id.constraint_layout_blue).setOnClickListener(this);
    }
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
    {
        View fragment1 = inflater.inflate(R.layout.fragment1, container, false); // Link view and layout
        return fragment1;
    }
    @Override
    public void onClick(View view)
    {
        if (view.getId() == R.id.constraint_layout_red) // If red constraint view gets clicked:
        {
            showToast("red button");
        }
        if (view.getId() == R.id.constraint_layout_blue) // If blue constraint view gets clicked:
        {
            showToast("blue button");
        }
    }
    public void showToast(String text)
    {
        Toast toast = Toast.makeText(getContext(), text, Toast.LENGTH_SHORT); // Generate toast message
        toast.setGravity(Gravity.CENTER| Gravity.CENTER, 0, -1); // Change y-Position of toast a bit
        toast.show(); // Show toast for 4 seconds
    }
}

Wenn ich versuche, den OnClickListener durch einen OnTouchListener zu ersetzen, weiß ich nicht, wie ich es coden soll.
Dieser Code hier funktioniert zwar, bringt mir aber nichts:
Code:
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;

public class Fragment1 extends Fragment implements View.OnTouchListener
{
    ConstraintLayout constraintLayoutRed, constraintLayoutBlue;
    @Override public void onResume()
    {
        super.onResume();
        constraintLayoutBlue = getActivity().findViewById(R.id.constraint_layout_blue); // Link variable to ID
        constraintLayoutRed = getActivity().findViewById(R.id.constraint_layout_red); // Link variable to ID
        getActivity().findViewById(R.id.constraint_layout_red).setOnTouchListener(this);
        getActivity().findViewById(R.id.constraint_layout_blue).setOnTouchListener(this);
    }
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
    {
        View fragment1 = inflater.inflate(R.layout.fragment1, container, false); // Link view and layout
        return fragment1;
    }
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent)
    {
        if (view.getId() == R.id.constraint_layout_red) // If red constraint view gets clicked:
        {
            showToast("red button");
        }
        if (view.getId() == R.id.constraint_layout_blue) // If blue constraint view gets clicked:
        {
            showToast("blue button");
        }
        return false;
    }
    public void showToast(String text)
    {
        Toast toast = Toast.makeText(getContext(), text, Toast.LENGTH_SHORT); // Generate toast message
        toast.setGravity(Gravity.CENTER| Gravity.CENTER, 0, -1); // Change y-Position of toast a bit
        toast.show(); // Show toast for 4 seconds
    }
}

Das ist die bisher beste Version, die ich hinbekommen habe:
Code:
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;

public class Fragment1 extends Fragment implements View.OnTouchListener
{
    ConstraintLayout constraintLayoutRed, constraintLayoutBlue;
    @Override public void onResume()
    {
        super.onResume();
        constraintLayoutBlue = getActivity().findViewById(R.id.constraint_layout_blue); // Link variable to ID
        constraintLayoutRed = getActivity().findViewById(R.id.constraint_layout_red); // Link variable to ID
        getActivity().findViewById(R.id.constraint_layout_red).setOnTouchListener(this);
        getActivity().findViewById(R.id.constraint_layout_blue).setOnTouchListener(this);
    }
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
    {
        View fragment1 = inflater.inflate(R.layout.fragment1, container, false); // Link view and layout
        return fragment1;
    }
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent)
    {
        if (view.getId() == R.id.constraint_layout_red) // If red constraint view gets clicked:
        {
            view.setOnTouchListener(new Gesten()
            {
                public boolean onClick()
                {
                    showToast("red button geklickt");
                    return false;
                }
                public boolean onSwipeTop()
                {
                    showToast("nach oben geswiped");
                    return false;
                }
                public boolean onSwipeBottom()
                {
                    showToast("nach unten geswiped");
                    return false;
                }
            });
        }
        if (view.getId() == R.id.constraint_layout_blue) // If blue constraint view gets clicked:
        {
            view.setOnTouchListener(new Gesten()
            {
                public boolean onClick()
                {
                    showToast("blue button geklickt");
                    return false;
                }
                public boolean onSwipeTop()
                {
                    showToast("nach oben geswiped");
                    return false;
                }
                public boolean onSwipeBottom()
                {
                    showToast("nach unten geswiped");
                    return false;
                }
            });
        }
        return false;
    }
    public void showToast(String text)
    {
        Toast toast = Toast.makeText(getContext(), text, Toast.LENGTH_SHORT); // Generate toast message
        toast.setGravity(Gravity.CENTER| Gravity.CENTER, 0, -1); // Change y-Position of toast a bit
        toast.show(); // Show toast for 4 seconds
    }
}

Lässt sich das evt. noch besser/kürzer schreiben?
Eigentlich wäre es mir lieber, wenn die SwipeUp/Down-Funktionen dem Fragment zugeordnet wären,
da ich für die Buttons keine extra Swipe Up/Down-Funktionen benötige.

Im obigen Beitrag war ja das Problem, dass die Buttons bzw. Views die Swipe-Gesten ignorieren.
Anders formuliert: Sie überdecken das fragment, welches die Swipe-Gesten erkennen soll.

Danke für jede Hilfe!
 
Hallo

Wurm eigentlich das ganze so kompliziert.
Ich habe mal das Beispiel genommen. Ein Fragment erstellt mit einem Button und einer TextView im Layout.
Wenn der Butten gedrückt wird also ein onKlick geht das und wenn ein Swip erkannt wird auch.

Klar wenn der Swip über ein klickbares View Elemente erfolgt wird er nicht erkannt ist aber in anderen App auch so.
Ansonsten musst du die Klick Auswertung auch selber machen.

Code:
public class MainFragment extends Fragment implements View.OnClickListener {

    View view;
    TextView text;

    public static MainFragment newInstance() {
        return new MainFragment();
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.main_fragment, container, false);
        text = view.findViewById(R.id.message1);
        Button bt = view.findViewById(R.id.button1);
        bt.setOnClickListener(this);

        view.setOnTouchListener(new Gesten(getActivity()) {
            @Override
            public boolean onSwipeTop() {
                text.setText("Swipe oben");
                //es wurde nach oben gewischt, hier den Code einfügen
                return true;
            }
            @Override
            public boolean onSwipeRight() {
                text.setText("Swipe rechts");
                //es wurde nach rechts gewischt, hier den Code einfügen
                return true;
            }
            @Override
            public boolean onSwipeLeft() {
                text.setText("Swipe links");
                //es wurde nach links gewischt, hier den Code einfügen
                return true;
            }
            @Override
            public boolean onSwipeBottom() {
                text.setText("Swipe unten");
                Toast.makeText(getActivity(), "Unten", Toast.LENGTH_SHORT).show();
                //es wurde nach unten gewischt, hier den Code einfügen
                return true;
            }
            @Override
            public boolean nichts(){
                text.setText("nichts");
                //es wurde keine wischrichtung erkannt, hier den Code einfügen
                return false;
            }
        });
        return view;
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.button1)
              text.setText("button gedrückt");
    }
}

Code:
public class Gesten implements View.OnTouchListener {

    private GestureDetector gestureDetector = null;
    private Context cxt = null;

    public Gesten(Context context) {
        gestureDetector = new GestureDetector(context, new GestureListener());
        cxt = context;
    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        boolean res = gestureDetector.onTouchEvent(event);
        return res;
    }

    private final class GestureListener extends GestureDetector.SimpleOnGestureListener {
        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            boolean result = false;
            try {
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                if (Math.abs(diffX) > Math.abs(diffY)) {
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffX > 0) {
                            result = onSwipeRight();
                        } else {
                            result = onSwipeLeft();
                        }
                    }else{
                        result = nichts();
                    }
                } else {
                    if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffY > 0) {
                            result = onSwipeBottom();
                        } else {
                            result = onSwipeTop();
                        }
                    }else{
                        result = nichts();
                    }
                }
            } catch (Exception exception) {
                exception.printStackTrace();
            }
            return result;
        }
    }
        public boolean onSwipeRight() {
            return false;
        }
        public boolean onSwipeLeft() {
            return false;
        }
        public boolean nichts() {
            return false;
        }
        public boolean onSwipeTop() {
            return false;
        }
        public boolean onSwipeBottom() {
            return false;
        }
}
 
  • Danke
Reaktionen: no1Ltan
Danke für die Tipps, ich schaue mir das morgen nochmal genauer an bzw. probiere es aus.
Das mit dem "Swipe funktioniert nicht, wenn man über ein klickbares View geht", ist aber wirklich ein Problem.

Ich hatte gerade eine andere Idee:
Ich fasse alle Views zusammen und weise ihnen die SwipeUp-Swipe-Down-Funktion hinzu.

Code:
@Override
    public boolean onTouch(View view, MotionEvent motionEvent)
    {
        if ((view.getId() == R.id.constraint_layout_one || (view.getId() == R.id.constraint_layout_two))) // If one constraint view gets clicked:
        {
            view.setOnTouchListener(new Gesten()
            {
                public boolean onSwipeTop()
                {
                    showToast("nach oben geswiped");
                    return false;
                }
                public boolean onSwipeBottom()
                {
                    showToast("nach unten geswiped");
                    return false;
                }
            });
        }
        if (view.getId() == R.id.constraint_layout_one) // If constraint one view gets clicked:
        {
            view.setOnTouchListener(new Gesten()
            {
                public boolean onClick()
                {
                    showToast("one button geklickt");
                    return false;
                }
            });
        }
        if (view.getId() == R.id.constraint_layout_two) // If constraint two view gets clicked:
        {
            view.setOnTouchListener(new Gesten()
            {
                public boolean onClick()
                {
                    showToast("two button geklickt");
                    return false;
                }
            });
        }
        return false;

Leider passiert nun gar nichts mehr, wenn ich über die 2 Views swipe.

Diese Varianten haben auch nicht funktioniert:
Code:
if (view.getId() == R.id.constraint_layout_one || view.getId() == R.id.constraint_layout_two)
Code:
if (view.getId() == R.id.constraint_layout_one || R.id.constraint_layout_two)

Danke für jede Hilfe!
 
sorry
 
Zuletzt bearbeitet:
Hallo,

du musst dich für nichts entschuldigen :)

Ich habe mal weiter rumgeforscht und einen kleinen Fortschritt gemacht.
Der OnClickListener und der OnTouchListener laufen gleichzeitig und der Code ist relativ kompakt.
Code:
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;

public class Fragment1 extends Fragment implements View.OnClickListener, View.OnTouchListener
{
    ConstraintLayout constraintLayoutOne, constraintLayoutTwo;
    @Override public void onResume()
    {
        super.onResume();
        constraintLayoutOne = getActivity().findViewById(R.id.constraint_layout_one); // Link variable to ID
        constraintLayoutTwo = getActivity().findViewById(R.id.constraint_layout_two); // Link variable to ID
        getActivity().findViewById(R.id.constraint_layout_one).setOnClickListener(this);
        getActivity().findViewById(R.id.constraint_layout_two).setOnClickListener(this);
        getActivity().findViewById(R.id.constraint_layout_one).setOnTouchListener(this);
        getActivity().findViewById(R.id.constraint_layout_two).setOnTouchListener(this);
    }
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
    {
        View fragment1 = inflater.inflate(R.layout.fragment1, container, false); // Link view and layout
        return fragment1;
    }
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent)
    {
        switch (view.getId())
        {
            case R.id.constraint_layout_one:
            case R.id.constraint_layout_two:
                view.setOnTouchListener(new Gesten()
                {
                    public boolean onSwipeTop()
                    {
                        showToast("nach oben geswiped");
                        return false;
                    }
                    public boolean onSwipeBottom()
                    {
                        showToast("nach unten geswiped");
                        return false;
                    }
                });
                break;
        }
        return false;
    }
    @Override
    public void onClick(View view)
    {
        if (view.getId() == R.id.constraint_layout_one) // If constraint view one gets clicked:
        {
            showToast("Button 1 geklickt");
        }
        if (view.getId() == R.id.constraint_layout_two) // If constraint view two gets clicked:
        {
            showToast("Button 2 geklickt");
        }
    }
    public void showToast(String text)
    {
        Toast toast = Toast.makeText(getContext(), text, Toast.LENGTH_SHORT); // Generate toast message
        toast.setGravity(Gravity.CENTER| Gravity.CENTER, 0, -1); // Change y-Position of toast a bit
        toast.show(); // Show toast for 4 seconds
    }
}

Leider gibt es aber noch ein Problem:
Die Click-Funktion läuft nur 1x.
Klicke ich auf die Buttons, erscheinen die Toasts.
Klicke ich erneut, passiert nichts mehr.

Beim Swipe ist es andersrum:
Swipe ich 1x, passiert nichts (egal ob nach oben oder unten).
Erst beim 2x funktionieren die Swipes.

Danke für jede Hilfe!
 
Das sorry war weil ich da einen Post hatte der da nicht hin solte und es nicht komplett löschen konnte.
 
Schon in Ordnung.
Ich hatte den Beitrag gesehen, konnte die Tipps aber nicht umsetzen.

Hast du zufällig ein Idee, wie ich das neue Problem lösen kann?
Danke nochmals!
 
Wenn du das so machst wie ich es gemacht habe geht es. Mit deinen zwei Layouts wird das nichts. Verabschiede dich davon.

Eine Verbesserung zu meinen letzten Code wäre. Das setzen der Buttonlistner nach dem Erstellen(Instanz) der Swipe Klasse zu machen.

Dann geht es auch wenn du beim Swipe außerhalb eines Button Startest und der Endpunkt ein Button ist.
Wenn der Startpunkt ein Button ist geht es nicht. Dazu müsstest du die onDown Methode in der GestureListener Klasse ändern.

Wie sieht den dein layout aus?
Es werden doch wohl nicht 30 Button in extremer größe sein. Etwas frei Raum für den Swipe sollte es schon geben.

Beiträge automatisch zusammengeführt:


Ps. Warum machst du das alles in der onResume?
Auch das erstellen der Instanz der Klasse gehört in die onCeateView und nicht in den Touchlistner. Die View die die du da bekommt ist nicht immer dein layout.
Wird nie richtig laufen.

Das gehört alles in onCeateView noch mal sage ich es nicht.

Auch warum noch den Touchlistner in der Fragment Klasse implementieren?
Denn hast du in der Swipe Klasse.


Noch etwas zum Verständnis.
Bei jedem Touchevent kommst du in deinen Listner an. Was machst du da?
Du erstellst jedes Mal eine neue Instanz der Swipe Klasse. Macht keinen sinn.
Bekommst auch immer die View wo dein Finger gerade war.
Nicht das ganze Layout.
Und wenn es eines der beiden Layouts ist erstellt du wieder eine neue Instanz der Klasse.
Das ist dann bei jeden Touch so.
Das es mit den Zwei Layouts sinnlos ist, solltest du schon selber bemerkt haben den bei beiden Layouts willst du die Instanz und den listner erstellen.
Hoffe das ist jetzt verstanden.

Noch etwas ich hatte dir auch erklärt was true und false in den Methoden bedeutet. Hast du auch nicht beachtet.

Wenn du deinen toast gemacht hast, hast du dich um das Event gekümmert und solltest true zurück geben.


Alles in allem ein großes durcheinander bei dir. Schaue dir die Beispiel richtig an.
 
Zuletzt bearbeitet:

Ähnliche Themen

F
  • Gesperrt
  • flamme1590
Antworten
1
Aufrufe
996
swa00
swa00
Tiefkuehlpizza
Antworten
2
Aufrufe
955
Tiefkuehlpizza
Tiefkuehlpizza
Zurück
Oben Unten