【问题标题】:Android. Swipe to back Activity like Telegram安卓。滑动回电报之类的活动
【发布时间】:2022-04-09 23:19:27
【问题描述】:

如何在 Telegram 和 Tinder 应用中使用手势和动画滑动到上一个活动?

【问题讨论】:

  • 你怎么知道那些是活动,而不是片段?
  • 好的,如何处理片段?

标签: android android-activity android-animation android-gesture


【解决方案1】:

Telegram 正在使用它自己创建的片段。他们创建了一个名为 ActionBarLayout 的类,它基本上是一个 FrameLayout 并添加到主 Activity 中,片段只是一个添加到 ActionBarLayout 的视图类(称为 TelegramFragment)(它们是保存在一个列表中,比普通片段快得多(功能少一点)。

要做动画,他们只是为添加的视图设置动画。

您可以看到 HEREHERE 的类在运行

【讨论】:

  • 嗨@snaky,我正在研究电报动画超过 2 个月,以便在我的 android 应用程序上应用相同的动画。我只需要“输入”和“输出”动画,例如当我们单击 DialogFragment 中的任何聊天时。我不会实现所有 ActionBarLayout 功能,例如 fragmentcontainer 和 stackcontainer(我知道这个功能非常重要) 我唯一的问题是:只有使用 ActionBarLayout.startLayoutAnimation 和 ActionBarLayout.onSlideAnimationEnd 我才能得到相同的电报动画?同样的醇厚?
【解决方案2】:

在 github 上有一个很好的库,我贡献了我的贡献:它通过活动和片段处理此功能。

https://github.com/r0adkll/Slidr

【讨论】:

  • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。
  • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
  • 这是一个库 (Slidr),链接是 github,它所在的位置。我无法通过在此处编写库的整个代码来回答,而且没有必要对使用方法进行介绍,因为它在自述文件中得到了很好的解释。
【解决方案3】:

其实你所要做的就是把这个 OnCreate:

getWindow().getDecorView().setBackgroundResource(android.R.color.transparent);
MIN_DISTANCE = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, this.getResources().getDisplayMetrics());
rootView = (ViewGroup) ((ViewGroup) this .findViewById(android.R.id.content)).getChildAt(0);
rootView.post(new Runnable() { @Override public void run() {
        
        rootWidth = rootView.getWidth();
    } });
}
// Custom Variables
ViewGroup rootView ;
int rootWidth;
boolean enableSwipe= false;
boolean lockSwipe = false;
float downX;
float downY;
float MIN_DISTANCE ;
// Detect touch Events
 @Override public boolean dispatchTouchEvent(MotionEvent event) { 
switch(event.getAction()) { 
    case MotionEvent.ACTION_DOWN: 
    downX = event.getRawX();
    downY =event.getRawY();
    enableSwipe = false;
    lockSwipe = false;
    //convert activity to transparent
    
    try {   java.lang.reflect.Method getActivityOptions = Activity.class.getDeclaredMethod("getActivityOptions"); getActivityOptions.setAccessible(true); Object options = getActivityOptions.invoke(this); Class<?>[] classes = Activity.class.getDeclaredClasses(); Class<?> translucentConversionListenerClazz = null; for (Class clazz : classes) { if (clazz.getSimpleName().contains("TranslucentConversionListener")) { translucentConversionListenerClazz = clazz; } } 
        java.lang.reflect.Method convertToTranslucent = Activity.class.getDeclaredMethod("convertToTranslucent", translucentConversionListenerClazz, ActivityOptions.class); convertToTranslucent.setAccessible(true); convertToTranslucent.invoke(this, null, options); } catch (Throwable t) {
    }
    break; 
    case MotionEvent.ACTION_MOVE: 
    if (!lockSwipe){
        if(enableSwipe){
            float translation = event.getRawX() -downX - MIN_DISTANCE;
            if (translation >= rootWidth || translation<= 0){
                rootView.setTranslationX(0);
            }else{
                rootView.setTranslationX(translation);
            }
        }else{
            float translation = event.getRawX() -downX;
            if(Math.abs(event.getRawY() - downY) >= MIN_DISTANCE){
                enableSwipe = false;
                lockSwipe = true;
            }else{
                enableSwipe = event.getRawX() -downX >= MIN_DISTANCE;
            }
        }
    }
    break; 
    case MotionEvent.ACTION_UP: 
    if(rootView.getTranslationX() > rootWidth / 5){
        rootView.animate() 
        .translationX(rootWidth)
        .setListener(
        new AnimatorListenerAdapter() { 
                    @Override public void onAnimationEnd(Animator animation) { 
                
                    super.onAnimationEnd(animation);
                finish();
                overridePendingTransition(0, 0);
                
            } });
    }else{
        rootView.animate() 
        .translationX(0)
        .setListener(
        new AnimatorListenerAdapter() { 
                    @Override public void onAnimationEnd(Animator animation) { 
                super.onAnimationEnd(animation);
                // convert activity back to normal
                try {
                                java.lang.reflect.Method method = Activity.class.getDeclaredMethod("convertFromTranslucent");
                                method.setAccessible(true);
                                method.invoke(this);
                            } catch (Throwable t) {
                            }
            } });
        enableSwipe =false;
        lockSwipe = false;
    }
    break; 
    default:
    enableSwipe =false;
    lockSwipe = false;
    break; 
}
if (enableSwipe){
    // Event will not be passed to next views
    return true;
}
else{
    // Event will be passed to next views
    return super.dispatchTouchEvent(event); 
}
}
{

【讨论】:

    【解决方案4】:

    导航库

    这是一个非常简单的库,与 NavComponent 完全集成。
    我仍在努力,但它已经很稳定,因此您可以在生产中使用它。

    https://github.com/massivemadness/Fragula
    (注意:它只适用于片段)

    首先,您需要在布局中将 NavHostFragment 替换为 FragulaNavHostFragment

    <!-- activity_main.xml -->
    <androidx.fragment.app.FragmentContainerView
        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="match_parent"
        android:name="com.fragula2.FragulaNavHostFragment" 
        android:id="@+id/nav_host"
        app:navGraph="@navigation/nav_graph"
        app:defaultNavHost="true" />
    

    其次,您需要将图中的&lt;fragment&gt; 目的地替换为&lt;swipeable&gt;,如下所示:

    <!-- nav_graph.xml -->
    <navigation 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/nav_graph"
        app:startDestination="@id/detailFragment">
    
        <swipeable
            android:id="@+id/detailFragment"
            android:name="com.example.fragula.DetailFragment"
            android:label="DetailFragment"
            tools:layout="@layout/fragment_detail" />
    
        ...
        
    </navigation>
    

    最后,您需要为片段的根布局设置不透明背景,以避免滑动动画出现任何问题。

    <!-- fragment_detail.xml -->
    <androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="?android:colorBackground">
        
        ...
        
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    基本上就是这样

    【讨论】:

      猜你喜欢
      • 2018-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-29
      • 2011-12-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多