Intereting Posts

Android – Как создать переход от элемента в списке к целому действию?

Я хочу, чтобы, когда пользователь щелкает элемент списка в ListView, он преобразуется в целую активность (как вы можете видеть в следующем примере), но я не смог найти учебник, объясняющий это, и, фактически, я делаю Не знаю, как это движение называется.

Другими словами, я хочу достичь:

  1. Увеличение высоты элемента списка при нажатии (как вы можете видеть в правом gif)

  2. Разверните и преобразуйте элемент списка в следующий макет фрагмента / действия, содержащий подробную информацию о клике

Введите описание изображения здесь Введите описание изображения здесь

Я пробовал много переходов, но не повезло. Может ли кто-нибудь помочь мне выполнить это?

Solutions Collecting From Web of "Android – Как создать переход от элемента в списке к целому действию?"

Я создаю небольшое примерное приложение, которое переходит между двумя действиями с желаемым эффектом: Пример приложения

Однако переходы в предоставленных gifs несколько отличаются. Переход в gif с левой стороны переводит элемент списка в область содержимого второго действия (панель инструментов остается на месте). В gif с правой стороны переход преобразует элемент списка в полный экран второго действия. Следующий код обеспечивает эффект в левом gif. Однако при этом необходимо будет адаптировать решение с небольшими изменениями для достижения перехода в правый gif.

Обратите внимание, что это работает только на Lollipop. Однако можно смело воздействовать на старые устройства. Кроме того, единственная цель предоставленного кода – показать, как это можно сделать. Не используйте это прямо в своем приложении.

Основная деятельность:

 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)); } } 

Итак, какие здесь разные части: у нас есть два вида деятельности. Во время перехода между видами деятельности переходят четыре вида.

  • Панель инструментов: как и в левой панели, панель инструментов не перемещается вместе с остальной частью содержимого.

  • Элемент ListView View -> становится представлением содержимого DetailActivity

  • StatusBar и NavigationBar Background: если мы не добавим эти представления к набору пересмотренных представлений, они будут исчезать и вернуться во время перехода. Однако это требует задержки перехода ввода (см. TransitionHelper.fixSharedElementTransitionForStatusAndNavigationBar )

В MainActivity переходные представления добавляются в Bundle, который используется для запуска функции DetailActivity . Кроме того, в обоих действиях необходимо называть пересмотренные представления ( transitionName ). Это можно сделать и в макете xml, а также программно.

Набор переходов по умолчанию, который используется во время перехода общего элемента, влияет на различные аспекты представления (например: границы просмотра – см. 2 ). Однако различия в возвышении зрения не анимируются. Вот почему представленное решение использует пользовательский ElevationTransition.

Попробуйте это .. 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()); } }); 

SharedElements

Анимация, которая вам нужна, называется Activity Transitions между общими элементами. По исследованиям я обнаружил, что вам следует:

  1. Поместите представление ListView в relativeLayout
  2. OnClick, раздуйте копию своего рендеринга
  3. Найти глобальные координаты, в которых средство визуализации находится во взаимодействии с родительским элементом ListView
  4. Добавьте скопированный рендеринг в RelativeLayout (родительский элемент ListView)
  5. Анимируйте списокView away
  6. В конце этого оживить, оживить ваш новый рендерер
  7. Прибыль!

      public class MainActivity extends 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); RelativeLayout.LayoutParams rlp = new 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) { // find out where the clicked view sits in relationship to the // parent container int t = view.getTop() + listView.getTop(); int l = view.getLeft() + listView.getLeft(); // create a copy of the listview and add it to the parent // container // at the same location it was in the listview selectedRenderer = new MyRenderer(view.getContext()); RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(view.getWidth(), view .getHeight()); rlp.topMargin = t; rlp.leftMargin = l; selectedRenderer.textView.setText(((MyRenderer) view).textView.getText()); layout.addView(selectedRenderer, rlp); view.setVisibility(View.INVISIBLE); // animate out the listView Animation outAni = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, -1f, Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f); outAni.setDuration(1000); outAni.setFillAfter(true); outAni.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { 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); } }); } public class MyAdapter extends 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 renderer; if (convertView != null) renderer = (MyRenderer) convertView; else renderer = new MyRenderer(MainActivity.this); renderer.textView.setText(getItem(position)); return renderer; } } public class MyRenderer extends RelativeLayout { public TextView textView; public MyRenderer(Context context) { super(context); setPadding(20, 20, 20, 20); setBackgroundColor(0xFFFF0000); RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); rlp.addRule(CENTER_IN_PARENT); textView = new TextView(context); addView(textView, rlp); } } } 

Попробуйте эту захватывающую веб-страницу @ Начало работы с действиями и переходы фрагментов (часть 1) . Здесь они рассказывали об активности и переходах фрагментов. Я не пробовал. Я считаю, что Fragment Transitions лучше и менее интенсивно работает в компьютере, поэтому это хороший старт. И вам, возможно, не придется менять панели инструментов, вы можете отображать / скрывать их.

Другая хорошая ссылка SO – это @ Анимация перехода между фрагментами , посмотрите на лучший ответ. В этом сообщении они говорили об объекте Animator .

Другое мнение о том, как вы разместили образец анимации, не показывает гладкую анимацию от одного искусства к другому. Это менее впечатляет, когда анимация негладкая.

Удачи, получайте удовольствие, держите нас всех в курсе.