尽管这个问题是重复的,但针对该问题提供的答案对许多观众来说并不适用,并且要求他们最终做出一些假设。
考虑到此功能存在于许多应用程序中,这是一个很好的问题,但是它需要一个非常详尽的答案。我将尝试将答案分解为一系列分隔的步骤,以确保它是可重复的!
问题
阻碍我们大多数人轻易做到这一点的问题是一种复合性质。为了完全理解这个问题,让我列出问题:
- 我们不应该使用典型的动画框架,因为
FragmentManager
和FragmentTransaction
类提供了一个方便的方法,setCustomAnimations(int, int, int int)
,它需要ObjectAnimators
- 此外,我们不能在
ObjectAnimators
(传统方法)中使用百分比标记
- 最后,我们只能在运行时确定屏幕宽度,因此必须在我们自己的布局中具有自定义功能
解决方案
为了解决这个问题并提供所需的沉浸式体验,我们必须从多个角度解决它。接下来的几个步骤准确地解释了如何获得这个功能!
我们首先需要为每个布局定义一个自定义布局,Fragment
因为我们必须在运行时访问屏幕的宽度,以及一个自包含的方法来View
根据此宽度操作(布局)的 x 位置。
FractionTranslateLinearLayout.java
public class FractionTranslateLinearLayout extends LinearLayout{
private int screenWidth;
private float fractionX;
protected void onSizeChanged(int w, int h, int oldW, int oldh){
// Assign the actual screen width to our class variable.
screenWidth = w;
super.onSizeChanged(w, h, oldW, oldH);
}
public float getFractionX(){
return fractionX;
}
public void setFractionX(float xFraction){
this.fractionX = xFraction;
// When we modify the xFraction, we want to adjust the x translation
// accordingly. Here, the scale is that if xFraction is -1, then
// the layout is off screen to the left, if xFraction is 0, then the
// layout is exactly on the screen, and if xFraction is 1, then the
// layout is completely offscreen to the right.
setX((screenWidth > 0) ? (xFraction * screenWidth) : 0);
}
}
现在,由于我们有一个特殊的布局,允许我们根据屏幕的物理宽度进行翻译,我们可以在相关的 Fragment XML 文件中使用它。
片段_1.xml
<com.[your_package_here].FractionTranslateLinearLayout
// Omitted namespace.
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/text_view_1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment 1" />
</com.[your_package_here].FractionTranslateLinearLayout>
片段_2.xml
<com.[your_package_here].FractionTranslateLinearLayout
// Omitted namespace.
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/text_view_2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment 2" />
</com.[your_package_here].FractionTranslateLinearLayout>
然后,我们必须创建Fragment
包含实现转换的逻辑的类。
片段1.java
public class Fragment1 extends Fragment {
public View onCreateView(LayoutInflater inf, ViewGroup vg, Bundle b){
// Simply inflate the View from the .xml file.
return inf.inflate(R.layout.fragment_1, vg, false);
}
}
片段2.java
public class Fragment2 extends Fragment {
public View onCreateView(LayoutInflater inf, ViewGroup vg, Bundle b){
// Simply inflate the View from the .xml file.
return inf.inflate(R.layout.fragment_2, vg, false);
}
public void onActivityCreated (Bundle savedInstanceState){
View v = getView();
FractionTranslateLinearLayout layout;
layout = (FractionTranslateLinearLayout) v.findViewById(R.id.layout);
// Move the entire View off to the right of the screen for now.
layout.setFractionX(1.0f);
}
}
现在让我们创建用于在屏幕上objectAnimator
转换 s 的 .xml 文件。View
请注意,我们将需要其中四个文件,因为我们需要一个用于每个进程(出和入),一个用于每一侧(左侧和右侧)。
slide_left_out.xml
<objectAnimator
// Omitted namespace.
android:valueFrom="0"
android:valueTo="-1"
// This String must be the exact name of the class variable.
android:propertyName="xFraction"
android:valueType="floatType"
// Duration in milliseconds.
android:duration="500"/>
slide_right_out.xml
<objectAnimator
// Omitted namespace.
android:valueFrom="0"
android:valueTo="1"
// This String must be the exact name of the class variable.
android:propertyName="xFraction"
android:valueType="floatType"
// Duration in milliseconds.
android:duration="500"/>
slide_left_in.xml
<objectAnimator
// Omitted namespace.
android:valueFrom="-1"
android:valueTo="0"
// This String must be the exact name of the class variable.
android:propertyName="xFraction"
android:valueType="floatType"
// Duration in milliseconds.
android:duration="500"/>
slide_right_in.xml
<objectAnimator
// Omitted namespace.
android:valueFrom="1"
android:valueTo="0"
// This String must be the exact name of the class variable.
android:propertyName="xFraction"
android:valueType="floatType"
// Duration in milliseconds.
android:duration="500"/>
请注意,这些文件夹必须放在项目结构中的“res/animator”目录中。
创建容器布局,Fragment
当我们在它们之间转换时将容纳它们。
主要的.xml
<com.android.FrameLayout
// Omitted namespace.
android:id="@+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
现在,我们必须创建Activity
将所有东西包装在一起的东西!
主.java
public class Main extends Activity {
private boolean showingFirstFragment;
public void onCreate(Bundle savedInstanceState){
setContentView(R.layout.main);
FragmentManager manager = getFragmentManager();
FragmentTransaction trans = manager.beginTransaction();
// Keep track of which Fragment we are facing.
showingFirstFragment = true;
// Add the first Fragment to the container.
trans.add(R.id.main_container, new Fragment1(), "fragment_1");
trans.commit();
}
public void onBackPressed(){
// Override the back button functionality to simply switch
// Fragments. Note that this would normally be done in a click
// click listener.
switchFragments();
}
private void switchFragments(){
FragmentManager manager = getFragmentManager();
FragmentTransaction trans = manager.beginTransaction();
// Set the animations that will emulate the functionality you
// requested.
int rightIn = R.animator.slide_right_in;
int rightOut = R.animator.slide_right_out;
int leftIn = R.animator.slide_left_in;
int leftOut = R.animator.slide_left_out;
// Note that we pass in 4 animations here. Please see the
// documentation on this method as it is critical to the
// understanding of this solution.
trans.setCustomAnimations(rightIn, leftOut, leftIn, rightOut);
if(showingFirstFragment){
int container = R.id.main_container;
// Show the second Fragment.
trans.replace(container, new Fragment2(), "fragment_2");
trans.commit();
showingFirstFragment = false;
}
else{
// Show the first Fragment by popping the back stack!
manager.popBackStack(null);
showingFirstFragment = true;
}
}
}
在这个代码示例中,这个类被大量使用。它的方法对于流程的执行至关重要!
一些注意事项
请注意,我在这里做了一些假设,并且这段代码非常独特:
- 此示例使用原始
Fragment
类,因此除非进行必要的修改,否则将无法与支持包一起使用。
- 此示例要求您使用
Android API 13.0
或以上。
- 这个例子的目的是提供信息,并希望能解释这里涉及的问题。在您自己的编辑器中拼凑代码是您应该自行决定的事情!
希望这里有足够的细节来回答你的问题。如果您需要更多,请告诉我。
此时,应该有足够的代码来实现您自己的解决方案。我确实在没有 Eclipse 编辑器的情况下输入了这个,所以如果有任何错误,请提前接受我的道歉!