问题描述
@H_502_0@我尝试在我的应用程序中的特定片段中实现Common Gestures检测机制。
@H_502_0@我已经实现了所有必需的onDown,onShowPress等方法。
手势检测器类已在onCreateView中启用。
@H_502_0@当用户执行这些手势之一时,应用程序应从也在此片段中实现的viewmodel实例调用转换方法。
@H_502_0@问题在于重写onTouchEvent。 AndroidStudio向我发送错误消息,指出onTouchEvent不会覆盖任何方法。
@H_502_0@我该如何解决这个问题?
@H_502_0@代码在这里:
@H_502_0@片段:
public class SecondFragment extends Fragment implements GestureDetector.OnGestureListener{
private Secondviewmodel mviewmodel;
private GestureDetectorCompat gDetector;
private final float rate = 3.14f;
public static SecondFragment newInstance() {
return new SecondFragment();
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater,@Nullable ViewGroup container,@Nullable Bundle savedInstanceState) {
gDetector = new GestureDetectorCompat(getActivity(),this);
return inflater.inflate(R.layout.second_fragment,container,false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mviewmodel = new viewmodelProvider(this).get(Secondviewmodel.class);
TextView euroView = getView().findViewById(R.id.inEuro);
TextView valueView = getView().findViewById(R.id.textView);
Switch mSwitch = getView().findViewById(R.id.mySwitch);
mSwitch.setonCheckedchangelistener(new CompoundButton.OnCheckedchangelistener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton,boolean isChecked) {
if (isChecked) {
Navigation.findNavController(mSwitch).navigate(R.id.movetoMain);
}
}
});
final Observer<Float> valueObserver = new Observer<Float>() {
@Override
public void onChanged(@Nullable final Float myValue) {
valueView.setText(myValue.toString());
}
};
final Observer<Float> eurovalueObserver = new Observer<Float>() {
@Override
public void onChanged(Float myValue) {
euroView.setText(myValue.toString());
}
};
mviewmodel.getValue().observe(getViewLifecycleOwner(),valueObserver);
mviewmodel.getEuroV().observe(getViewLifecycleOwner(),eurovalueObserver);
}
@Override
public void onStart(){
super.onStart();
mviewmodel.setValue(SecondFragmentArgs.fromBundle(getArguments()).getVal());
}
@Override
public boolean onDown(MotionEvent motionEvent) {
mviewmodel.convertion();
return false;
}
@Override
public void onShowPress(MotionEvent motionEvent) {
}
@Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
mviewmodel.convertion();
return false;
}
@Override
public boolean onScroll(MotionEvent motionEvent,MotionEvent motionEvent1,float v,float v1) {
mviewmodel.convertion();
return false;
}
@Override
public void onLongPress(MotionEvent motionEvent) {
}
@Override
public boolean onFling(MotionEvent motionEvent,float v1) {
mviewmodel.convertion();
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
this.gDetector.onTouchEvent(event);
return getActivity().onTouchEvent(event);
}
@H_502_0@}
@H_502_0@ 更新
@H_502_0@ 具有onTouch方法的解决方案
@SuppressLint("ClickableViewAccessibility")
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mviewmodel = new viewmodelProvider(this).get(Secondviewmodel.class);
secondFrag = getView().findViewById(R.id.ConstraintLayout);
euroView = getView().findViewById(R.id.inEuro);
valueView = getView().findViewById(R.id.textView);
mSwitch = getView().findViewById(R.id.mySwitch);
mSwitch.setonCheckedchangelistener(new CompoundButton.OnCheckedchangelistener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton,boolean isChecked) {
if (isChecked) {
Navigation.findNavController(mSwitch).navigate(R.id.movetoMain);
}
}
});
secondFrag.setonTouchListener(new View.OnTouchListener() {
GestureDetectorCompat gDetector = new GestureDetectorCompat(getActivity(),new GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent p1) {
euroView.setText("true");
return true;
}
@Override
public void onShowPress(MotionEvent p1) {
// Todo: Implement this method
}
@Override
public boolean onSingleTapUp(MotionEvent p1) {
euroView.setText("true");
return true;
}
@Override
public boolean onScroll(MotionEvent p1,MotionEvent p2,float p3,float p4) {
euroView.setText("true");
return true;
}
@Override
public void onLongPress(MotionEvent p1) {
// Todo: Implement this method
}
@Override
public boolean onFling(MotionEvent p1,float p4) {
// Todo: Implement this method
return false;
}
});
@Override
public boolean onTouch(View view,MotionEvent motionEvent) {
secondFrag.onTouchEvent(motionEvent);
return true;
}
});
@H_502_0@主机活动的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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
@H_502_0@片段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:id="@+id/ConstraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SecondFragment">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2ndFragmentWithviewmodel"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.456" />
<Switch
android:id="@+id/mySwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Switch"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/inEuro"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="67dp"
android:text="MyTextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="0.17000002" />
</androidx.constraintlayout.widget.ConstraintLayout>
解决方法
首先,初始化您的父视图:
private FrameLayout parentView;
parentView = getView().findViewById(R.id.parent_view);
然后为其设置一个触摸侦听器:
parentView.setOnTouchListener( new View.OnTouchListener() {
GestureDetectorCompat gDetector = new GestureDetectorCompat(getActivity(),new GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent p1) {
// TODO: Implement this method
return false;
}
@Override
public void onShowPress(MotionEvent p1) {
// TODO: Implement this method
}
@Override
public boolean onSingleTapUp(MotionEvent p1) {
// TODO: Implement this method
return false;
}
@Override
public boolean onScroll(MotionEvent p1,MotionEvent p2,float p3,float p4) {
// TODO: Implement this method
return false;
}
@Override
public void onLongPress(MotionEvent p1) {
// TODO: Implement this method
}
@Override
public boolean onFling(MotionEvent p1,float p4) {
// TODO: Implement this method
return false;
}
});
@Override
public boolean onTouch(View p1,MotionEvent p2) {
// TODO: Implement this method
return false;
}
});
主机活动的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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
片段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:id="@+id/ConstraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SecondFragment">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2ndFragmentWithViewModel"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.456" />
<Switch
android:id="@+id/mySwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Switch"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/inEuro"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="67dp"
android:text="MyTextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="0.17000002" />
</androidx.constraintlayout.widget.ConstraintLayout>
,
所以,最后我想出了一个解决方案。
为了实现特定的片段手势检测,例如向右,向左滑动等。我们大概不能使用GesturDetectorCompat类。作为替代,我发现编写了自己的CommonGestureDetector类。 内容如下:
public class OnSwipeListener implements View.OnTouchListener{
private final GestureDetector gestureDetector;
public OnSwipeListener(Context context){
gestureDetector = new GestureDetector(context,new GestureListener());
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View view,MotionEvent motionEvent) {
return gestureDetector.onTouchEvent(motionEvent);
}
private final class GestureListener extends GestureDetector.SimpleOnGestureListener{
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
private static final int SWIPE_THRESHOLD = 100;
@Override
public boolean onDown(MotionEvent e){return true;}
@Override
public boolean onFling(MotionEvent e1,MotionEvent e2,float velocityX,float velocityY) {
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) {
onSwipeRight();
} else {
onSwipeLeft();
}
}
} else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
onSwipeBottom();
} else {
onSwipeTop();
}
}
return true;
}
}
public void onSwipeRight() {
}
public void onSwipeLeft() {
}
public void onSwipeTop() {
}
public void onSwipeBottom() {
}
}
它的来源来自这里:https://riptutorial.com/android/example/16543/swipe-detection
这是我们自己的GestureDetectorCompat实现,完全适合Fragments,并且我们仍保持项目类代码“干净整洁”。
它在我的应用中的外观:
public class MainFragment extends Fragment {
private MainViewModel mViewModel;
public static MainFragment newInstance() {
return new MainFragment();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,@Nullable ViewGroup container,@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.main_fragment,container,false);
TextView textView = view.findViewById(R.id.testView);
view.setOnTouchListener(new OnSwipeListener(getContext()){
public void onSwipeTop()
{
textView.setText("top");
}
public void onSwipeRight()
{textView.setText("right");}
public void onSwipeLeft(){textView.setText("left");}
public void onSwipeBottom(){textView.setText("bottom");}
});
return view;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = new ViewModelProvider(this).get(MainViewModel.class);
// TODO: Use the ViewModel
}
}
因此,如您所见,前面提到的类作为参数传递给我们的片段的OnActivityCreated方法中的setOnTouchListener,而花费最少的精力来编写它:)
我希望有一天能对某人有所帮助:)
非常感谢@AliEid对我的问题感兴趣。