首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Android -如何创建从列表视图中的项目到整个活动的过渡?

Android -如何创建从列表视图中的项目到整个活动的过渡?
EN

Stack Overflow用户
提问于 2015-10-28 23:19:20
回答 4查看 17.5K关注 0票数 28

我想要的是,当用户单击ListView中的一个列表项时,它会转换为一个完整的活动(如您在下面的示例中所看到的),但是我找不到一个教程来解释这一点,实际上,我不知道这个移动是如何调用的。

换句话说,我想要实现的是:

  1. 在单击列表项时增加列表项的高度(如您在右侧gif中所见)
  2. 展开列表项并将其转换为下一个片段/活动布局,其中包含有关单击的项的详细信息

我已经尝试了很多转换,但都没有成功。有人能帮我完成这件事吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-11-06 09:14:26

我构建了一个小的示例应用程序,它可以在两个活动之间进行转换,并达到预期的效果:

但是,所提供的gif中的过渡略有不同。左侧gif中的转换将列表元素转换到第二个活动的内容区域(工具栏保持不变)。在右侧的gif中,转换将列表元素转换为第二个活动的完整屏幕。下面的代码提供了左侧gif中的效果。但是,应该可以通过较小的修改来调整解决方案,以实现正确的gif中的过渡。

注意:这只适用于棒棒糖。然而,在较老的设备上模拟不同的效果是可能的。此外,提供的代码的唯一目的是展示如何实现它。不要直接在你的应用中使用它。

MainActivity:

public class MainActivity extends AppCompatActivity {

    MyAdapter myAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
        ListView listView = (ListView) findViewById(R.id.list_view);

        myAdapter = new MyAdapter(this, 0, DataSet.get());

        listView.setAdapter(myAdapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, final View view, final int position, long id) {
                startTransition(view, myAdapter.getItem(position));
            }
        });
    }

    private void startTransition(View view, Element element) {
        Intent i = new Intent(MainActivity.this, DetailActivity.class);
        i.putExtra("ITEM_ID", element.getId());

        Pair<View, String>[] transitionPairs = new Pair[4];
        transitionPairs[0] = Pair.create(findViewById(R.id.toolbar), "toolbar"); // Transition the Toolbar
        transitionPairs[1] = Pair.create(view, "content_area"); // Transition the content_area (This will be the content area on the detail screen)

        // We also want to transition the status and navigation bar barckground. Otherwise they will flicker
        transitionPairs[2] = Pair.create(findViewById(android.R.id.statusBarBackground), Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME);
        transitionPairs[3] = Pair.create(findViewById(android.R.id.navigationBarBackground), Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME);
        Bundle b = ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this, transitionPairs).toBundle();

        ActivityCompat.startActivity(MainActivity.this, i, b);
    }
}

activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimary"
        android:transitionName="toolbar" />

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

DetailActivity:

public class DetailActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);

        setSupportActionBar((Toolbar) findViewById(R.id.toolbar));

        long elementId = getIntent().getLongExtra("ITEM_ID", -1);
        Element element = DataSet.find(elementId);


        ((TextView) findViewById(R.id.title)).setText(element.getTitle());
        ((TextView) findViewById(R.id.description)).setText(element.getDescription());

        // if we transition the status and navigation bar we have to wait till everything is available
        TransitionHelper.fixSharedElementTransitionForStatusAndNavigationBar(this);
        // set a custom shared element enter transition
        TransitionHelper.setSharedElementEnterTransition(this, R.transition.detail_activity_shared_element_enter_transition);
    }
}

activity_detail.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimary"
        android:transitionName="toolbar" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#abc"
        android:orientation="vertical"
        android:paddingBottom="200dp"
        android:transitionName="content_area"
        android:elevation="10dp">

        <TextView
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/description"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
</LinearLayout>

detail_activity_shared_element_enter_transition.xml (/res/transition/):

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    android:transitionOrdering="together">
    <changeBounds/>
    <changeTransform/>
    <changeClipBounds/>
    <changeImageTransform/>
    <transition class="my.application.transitions.ElevationTransition"/>
</transitionSet>

my.application.transitions.ElevationTransition:

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class ElevationTransition extends Transition {

    private static final String PROPNAME_ELEVATION = "my.elevation:transition:elevation";

    public ElevationTransition() {
    }

    public ElevationTransition(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void captureStartValues(TransitionValues transitionValues) {
        captureValues(transitionValues);
    }

    @Override
    public void captureEndValues(TransitionValues transitionValues) {
        captureValues(transitionValues);
    }

    private void captureValues(TransitionValues transitionValues) {
        Float elevation = transitionValues.view.getElevation();
        transitionValues.values.put(PROPNAME_ELEVATION, elevation);
    }

    @Override
    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
        if (startValues == null || endValues == null) {
            return null;
        }

        Float startVal = (Float) startValues.values.get(PROPNAME_ELEVATION);
        Float endVal = (Float) endValues.values.get(PROPNAME_ELEVATION);
        if (startVal == null || endVal == null || startVal.floatValue() == endVal.floatValue()) {
            return null;
        }

        final View view = endValues.view;
        ValueAnimator a = ValueAnimator.ofFloat(startVal, endVal);
        a.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                view.setElevation((float)animation.getAnimatedValue());
            }
        });

        return a;
    }
}

TransitionHelper:

public class TransitionHelper {

    public static void fixSharedElementTransitionForStatusAndNavigationBar(final Activity activity) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
            return;

        final View decor = activity.getWindow().getDecorView();
        if (decor == null)
            return;
        activity.postponeEnterTransition();
        decor.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @TargetApi(Build.VERSION_CODES.LOLLIPOP)
            @Override
            public boolean onPreDraw() {
                decor.getViewTreeObserver().removeOnPreDrawListener(this);
                activity.startPostponedEnterTransition();
                return true;
            }
        });
    }

    public static void setSharedElementEnterTransition(final Activity activity, int transition) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
            return;
        activity.getWindow().setSharedElementEnterTransition(TransitionInflater.from(activity).inflateTransition(transition));
    }
}

那么这里的不同部分是什么:我们有两个活动。在转换期间,四个视图在活动之间转换。

  • 工具栏:就像在左边的gif中一样,如果工具栏没有随着元素视图的其余部分移动,那么它将成为DetailActivity
  • StatusBar和NavigationBar背景的内容视图:如果我们不将这些视图添加到转换的视图集合中,它们将在转换过程中淡出和淡入。但是,这需要延迟enter转换(请参阅:TransitionHelper.fixSharedElementTransitionForStatusAndNavigationBar)

MainActivity中,转换后的视图被添加到用于启动DetailActivity的包中。此外,在这两个活动中,转换后的视图都需要命名为(transitionName)。这可以在布局xml中完成,也可以通过编程完成。

在共享元素转换期间使用的默认转换集会影响视图的不同方面(例如:视图边界-请参阅2)。但是,视图的高程差异不是动画。这就是所展示的解决方案使用自定义ElevationTransition的原因。

票数 18
EN

Stack Overflow用户

发布于 2015-10-29 01:17:20

试试这个..。Material-Animations

blueIconImageView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent i = new Intent(MainActivity.this, SharedElementActivity.class);

        View sharedView = blueIconImageView;
        String transitionName = getString(R.string.blue_name);

        ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, sharedView, transitionName);
        startActivity(i, transitionActivityOptions.toBundle());
    }
});

票数 6
EN

Stack Overflow用户

发布于 2015-11-04 01:30:27

您需要的动画称为共享元素之间的活动过渡。通过研究,我发现你应该:

relativeLayout

  • OnClick,

  • Put your ListView view in a relativeLayout

  • OnClick,放大渲染器的副本

  • 查找渲染器所处位置的全局坐标(相对于ListView)

  • Animate renderer

  • Profit!的父级)

  • 将复制的渲染器添加到RelativeLayout (ListView)

  • Animate listView away

  • 的父级在该动画的末尾,设置新动画的动画

公共类MainActivity扩展Activity { private RelativeLayout layout;private ListView listView;private MyRenderer selectedRenderer;@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);layout = new RelativeLayout(this);setContentView(layout);listView = new ListView(this);新建rlp = RelativeLayout.LayoutParams RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT);layout.addView(listView,rlp);listView.setAdapter(new MyAdapter());listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent,View view,int position,long id) { //找出点击的视图相对于//父容器的位置int t= view.getTop() + listView.getTop();int l= view.getLeft() + listView.getLeft();//创建列表视图的副本,并将其添加到父//容器中//与列表视图中的位置相同的容器selectedRenderer =view.getLeft(view.getContext());视图rlp = selectedRenderer.textView.setText(((MyRenderer) RelativeLayout.LayoutParams(view.getWidth(),RelativeLayout.LayoutParams .getHeight());rlp.topMargin = t;rlp.leftMargin = l;视图.textView.getText());layout.addView(selectedRenderer,rlp);view.setVisibility(View.INVISIBLE);//动画输出listView动画outAni =listView outAni 0f,Animation.RELATIVE_TO_SELF,-1f,Animation.RELATIVE_TO_SELF,0f,Animation.RELATIVE_TO_SELF,0f);outAni.setDuration(1000);outAni.setFillAfter(true);OutAni.setAnimationListener(新的Animation.AnimationListener() { @Override public void onAnimationStart(动画动画){} @Override public void onAnimationRepeat(动画动画){} @Override public void onAnimationEnd(动画动画){ ScaleAnimation scaleAni = new ScaleAnimation(1f,1f,1f,2f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);scaleAni.setDuration(400);scaleAni.setFillAfter(true);selectedRenderer.startAnimation(scaleAni);} });listView.startAnimation(outAni);} });}公共类MyAdapter扩展BaseAdapter { @Override public int getCount() { return 10;} @Override public String getItem(int position) { return "Hello World“+ position;} @Override public long getItemId(int position) { return position;} @Override public View getView(int position,View convertView,ViewGroup parent) { MyRenderer渲染器;if (convertView != null)渲染器= (MyRenderer) convertView;else渲染器=新位置( MyRenderer );renderer.textView.setText(getItem(MainActivity.this));return渲染器;}}公共类MyRenderer扩展RelativeLayout {公共上下文上下文;公共上下文( TextView TextView){ MyRenderer( context );setPadding(20,20,20,20);setBackgroundColor(0xFFFF0000);RelativeLayout.LayoutParams rlp =新RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT);rlp.addRule(CENTER_IN_PARENT);textView =新textView(上下文);addView(textView,rlp);}

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33394926

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档