Blog para desarrollo de aplicaciones en Android, aprende paso a paso como crear aplicaciones.

Usamos cookies propias y de terceros que entre otras cosas recogen datos sobre sus hábitos de navegación para mostrarle publicidad personalizada y realizar análisis de uso de nuestro sitio.
Si continúa navegando consideramos que acepta su uso. OK Más información | Y más

Como crear un ViewPager Cards en Android inspirado en Duolingo

Android ViewPager Cards inspirado en Duolingo Example


Hola amigos en esta ocasión vamos a aprender a utilizar ViewPager. para mostrar Cards de forma similar a la aplicación Duolingo App!

Vamos a crear nuestro ejemplo.


Crear Emulador AVD. (Aquí)

Crearemos un emulador AVD para desarrollar nuestro ejemplo ViewPager.
Android Studio - ViewPager Cards inspirado en Duolingo


ViewPager Layout Design

Comenzaremos agregando el siguiente Style para nuestra aplicación nos dirigimos a la carpeta res - values - style.xml y agregamos lo siguiente.
style del Button Duolingo App.


<style name="ButtonStyle" parent="Base.Widget.AppCompat.Button.Colored">
 <item name="colorButtonNormal">@color/colorAccent</item>
</style>

Y en la misma carpeta res - values - dimens.xml agregaremos la siguiente dimensión.

<dimen name="card_padding">60dp</dimen>

Ahora en el archivo strin.xml agregaremos lo siguiente

<string name="title_1">Card Title 1</string>
<string name="title_2">Card Title 2</string>
<string name="title_3">Card Title 3</string>
<string name="title_4">Card Title 4</string>

<string name="text_1">ViewPager App Duolingo</string>
Con esto avanzaremos a nuestro diseño y en res - layout - activity_main.xml crearemos el diseño.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginTop="16dp"
android:gravity="center"
android:orientation="vertical">

<Button
android:id="@+id/cardTypeBtn"
style="@style/ButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Fragments" />

<CheckBox
android:id="@+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Scale" />
</LinearLayout>

<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="330dp"
android:layout_gravity="bottom"
android:clipToPadding="false"
android:overScrollMode="never"
android:paddingBottom="30dp"
android:paddingEnd="@dimen/card_padding"
android:paddingLeft="@dimen/card_padding"
android:paddingRight="@dimen/card_padding"
android:paddingStart="@dimen/card_padding" />
</RelativeLayout>

El diseño quedaría de la siguiente manera este sera para nuestro ViewPager y donde se mostraran las Cards al estilo de la App Duolingo. Pero antes de esto vamos a ir al archivo. Gradle Scripts y luego build.gradle (Module:app) y agregaremos la siguiente dependencia.
Android Studio - ViewPager Cards inspirado en Duolingo

compile 'com.android.support:cardview-v7:25.1.0'
Ahora crearemos el adapter.xml en la carpeta Layouts. Y quedaría de la siguiente manera. Y dentro de la carpeta Drawable crearemos el siguiente archivo ic_bookmark.xml.


<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 android:id="@+id/cardView"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_gravity="center"
 app:cardUseCompatPadding="true">

 <FrameLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content">


 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:gravity="center"
 android:orientation="vertical"
 android:padding="24dp">

 <TextView
 android:id="@+id/titleTextView"
 style="@style/TextAppearance.AppCompat.Title"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" />

 <TextView
 android:id="@+id/contentTextView"
 style="@style/TextAppearance.AppCompat.Body1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginTop="24dp"/>

 <Button
 style="@style/ButtonStyle"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_marginTop="24dp"
 android:text="Button" />
 </LinearLayout>

 <ImageView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_gravity="top|end"
 android:layout_marginEnd="8dp"
 android:layout_marginRight="8dp"
 android:layout_marginTop="-5dp"
 android:src="@drawable/ic_bookmark_24dp" />

 </FrameLayout>

</android.support.v7.widget.CardView>

Android Studio - ViewPager Cards inspirado en Duolingo

ic_bookmark.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
 android:width="36dp"
 android:height="36dp"
 android:viewportWidth="24.0"
 android:viewportHeight="24.0">
 <path
 android:fillColor="#ffffb84d"
 android:pathData="M17,3H7c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3V5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
Android Studio - ViewPager Cards inspirado en Duolingo
Y para terminar con el diseño agregaremos en res - layout - fragment_adapter.xml


<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 android:id="@+id/cardView"
 app:cardUseCompatPadding="true"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_gravity="center">

 <FrameLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content">


 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:gravity="center"
 android:orientation="vertical"
 android:padding="24dp">

 <TextView
 style="@style/TextAppearance.AppCompat.Title"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Card title" />

 <TextView
 style="@style/TextAppearance.AppCompat.Body1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginTop="24dp"
 android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eget ligula eu lectus lobortis condimentum." />

 <Button
 style="@style/ButtonStyle"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_marginTop="24dp"
 android:text="Button" />
 </LinearLayout>

 <ImageView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_gravity="top|start"
 android:layout_marginStart="8dp"
 android:layout_marginLeft="8dp"
 android:layout_marginTop="-5dp"
 android:src="@drawable/ic_bookmark" />

 </FrameLayout>

</android.support.v7.widget.CardView>

El diseño quedaria de la siguiente manera igual quela App Duolingo.
Android Studio - ViewPager Cards inspirado en Duolingo
Ahora continuaremos con el código para nuestra aplicación.

ViewPager MaintActivity Code App Duolingo


Agregaremos la siguiente clase CardAdapter.




import android.support.v7.widget.CardView;

public interface CardAdapter {

 int MAX_ELEVATION_FACTOR = 8;

 float getBaseElevation();

 CardView getCardViewAt(int position);

 int getCount();
}
Y luego para nuestra aplicación la siguiente clase ShadowTransformer.


import android.support.v4.view.ViewPager;
import android.support.v7.widget.CardView;
import android.view.View;


public class ShadowTransformer implements ViewPager.OnPageChangeListener, ViewPager.PageTransformer {

 private ViewPager mViewPager;
 private CardAdapter mAdapter;
 private float mLastOffset;
 private boolean mScalingEnabled;

 public ShadowTransformer(ViewPager viewPager, CardAdapter adapter) {
 mViewPager = viewPager;
 viewPager.addOnPageChangeListener(this);
 mAdapter = adapter;
 }

 public void enableScaling(boolean enable) {
 if (mScalingEnabled && !enable) {
 // shrink main card
 CardView currentCard = mAdapter.getCardViewAt(mViewPager.getCurrentItem());
 if (currentCard != null) {
 currentCard.animate().scaleY(1);
 currentCard.animate().scaleX(1);
 }
 }else if(!mScalingEnabled && enable){
 // grow main card
 CardView currentCard = mAdapter.getCardViewAt(mViewPager.getCurrentItem());
 if (currentCard != null) {
 currentCard.animate().scaleY(1.1f);
 currentCard.animate().scaleX(1.1f);
 }
 }

 mScalingEnabled = enable;
 }

 @Override
 public void transformPage(View page, float position) {

 }

 @Override
 public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
 int realCurrentPosition;
 int nextPosition;
 float baseElevation = mAdapter.getBaseElevation();
 float realOffset;
 boolean goingLeft = mLastOffset > positionOffset;

 // If we're going backwards, onPageScrolled receives the last position
 // instead of the current one
 if (goingLeft) {
 realCurrentPosition = position + 1;
 nextPosition = position;
 realOffset = 1 - positionOffset;
 } else {
 nextPosition = position + 1;
 realCurrentPosition = position;
 realOffset = positionOffset;
 }

 // Avoid crash on overscroll
 if (nextPosition > mAdapter.getCount() - 1
 || realCurrentPosition > mAdapter.getCount() - 1) {
 return;
 }

 CardView currentCard = mAdapter.getCardViewAt(realCurrentPosition);

 // This might be null if a fragment is being used
 // and the views weren't created yet
 if (currentCard != null) {
 if (mScalingEnabled) {
 currentCard.setScaleX((float) (1 + 0.1 * (1 - realOffset)));
 currentCard.setScaleY((float) (1 + 0.1 * (1 - realOffset)));
 }
 currentCard.setCardElevation((baseElevation + baseElevation
 * (CardAdapter.MAX_ELEVATION_FACTOR - 1) * (1 - realOffset)));
 }

 CardView nextCard = mAdapter.getCardViewAt(nextPosition);

 // We might be scrolling fast enough so that the next (or previous) card
 // was already destroyed or a fragment might not have been created yet
 if (nextCard != null) {
 if (mScalingEnabled) {
 nextCard.setScaleX((float) (1 + 0.1 * (realOffset)));
 nextCard.setScaleY((float) (1 + 0.1 * (realOffset)));
 }
 nextCard.setCardElevation((baseElevation + baseElevation
 * (CardAdapter.MAX_ELEVATION_FACTOR - 1) * (realOffset)));
 }
 mLastOffset = positionOffset;
 }
 @Override
 public void onPageSelected(int position) {
 }
 @Override
 public void onPageScrollStateChanged(int state) {
 }
}

Agregaremos CardItem,


public class CardItem {

 private int mTextResource;
 private int mTitleResource;

 public CardItem(int title, int text) {
 mTitleResource = title;
 mTextResource = text;
 }

 public int getText() {
 return mTextResource;
 }

 public int getTitle() {
 return mTitleResource;
 }
}
Y luego CardPagerAdapter


import android.support.v4.view.PagerAdapter;
import android.support.v7.widget.CardView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class CardPagerAdapter extends PagerAdapter implements CardAdapter {

 private List<CardView> mViews;
 private List<CardItem> mData;
 private float mBaseElevation;

 public CardPagerAdapter() {
 mData = new ArrayList<>();
 mViews = new ArrayList<>();
 }

 public void addCardItem(CardItem item) {
 mViews.add(null);
 mData.add(item);
 }

 public float getBaseElevation() {
 return mBaseElevation;
 }

 @Override
 public CardView getCardViewAt(int position) {
 return mViews.get(position);
 }

 @Override
 public int getCount() {
 return mData.size();
 }

 @Override
 public boolean isViewFromObject(View view, Object object) {
 return view == object;
 }

 @Override
 public Object instantiateItem(ViewGroup container, int position) {
 View view = LayoutInflater.from(container.getContext())
 .inflate(R.layout.adapter, container, false);
 container.addView(view);
 bind(mData.get(position), view);
 CardView cardView = (CardView) view.findViewById(R.id.cardView);

 if (mBaseElevation == 0) {
 mBaseElevation = cardView.getCardElevation();
 }

 cardView.setMaxCardElevation(mBaseElevation * MAX_ELEVATION_FACTOR);
 mViews.set(position, cardView);
 return view;
 }

 @Override
 public void destroyItem(ViewGroup container, int position, Object object) {
 container.removeView((View) object);
 mViews.set(position, null);
 }

 private void bind(CardItem item, View view) {
 TextView titleTextView = (TextView) view.findViewById(R.id.titleTextView);
 TextView contentTextView = (TextView) view.findViewById(R.id.contentTextView);
 titleTextView.setText(item.getTitle());
 contentTextView.setText(item.getText());
 }

}
Luego de esto agregaremos la siguiente clase. CardFragment



import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.CardView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


public class CardFragment extends Fragment {

 private CardView mCardView;

 @Nullable
 @Override
 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
 @Nullable Bundle savedInstanceState) {
 View view = inflater.inflate(R.layout.fragment_adapter, container, false);
 mCardView = (CardView) view.findViewById(R.id.cardView);
 mCardView.setMaxCardElevation(mCardView.getCardElevation()
 * CardAdapter.MAX_ELEVATION_FACTOR);
 return view;
 }

 public CardView getCardView() {
 return mCardView;
 }
}

Y para terminar agregaremos CardFragmentPagerAdapter


import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v7.widget.CardView;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

public class CardFragmentPagerAdapter extends FragmentStatePagerAdapter implements CardAdapter {

 private List<CardFragment> mFragments;
 private float mBaseElevation;

 public CardFragmentPagerAdapter(FragmentManager fm, float baseElevation) {
 super(fm);
 mFragments = new ArrayList<>();
 mBaseElevation = baseElevation;

 for(int i = 0; i< 5; i++){
 addCardFragment(new CardFragment());
 }
 }

 @Override
 public float getBaseElevation() {
 return mBaseElevation;
 }

 @Override
 public CardView getCardViewAt(int position) {
 return mFragments.get(position).getCardView();
 }

 @Override
 public int getCount() {
 return mFragments.size();
 }

 @Override
 public Fragment getItem(int position) {
 return mFragments.get(position);
 }

 @Override
 public Object instantiateItem(ViewGroup container, int position) {
 Object fragment = super.instantiateItem(container, position);
 mFragments.set(position, (CardFragment) fragment);
 return fragment;
 }

 public void addCardFragment(CardFragment fragment) {
 mFragments.add(fragment);
 }

}
Y por ultimo agregaremos en nuestro MaintActivity.

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;

public class MainActivity extends AppCompatActivity implements View.OnClickListener,
CompoundButton.OnCheckedChangeListener {

private Button mButton;
private ViewPager mViewPager;
private CardPagerAdapter mCardAdapter;
private ShadowTransformer mCardShadowTransformer;
private CardFragmentPagerAdapter mFragmentCardAdapter;
private ShadowTransformer mFragmentCardShadowTransformer;
private boolean mShowingFragments = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.viewPager);
mButton = (Button) findViewById(R.id.cardTypeBtn);
((CheckBox) findViewById(R.id.checkBox)).setOnCheckedChangeListener(this);
mButton.setOnClickListener(this);

mCardAdapter = new CardPagerAdapter();
mCardAdapter.addCardItem(new CardItem(R.string.title_1, R.string.text_1));
mCardAdapter.addCardItem(new CardItem(R.string.title_2, R.string.text_1));
mCardAdapter.addCardItem(new CardItem(R.string.title_3, R.string.text_1));
mCardAdapter.addCardItem(new CardItem(R.string.title_4, R.string.text_1));
mFragmentCardAdapter = new CardFragmentPagerAdapter(getSupportFragmentManager(),
dpToPixels(2, this));

mCardShadowTransformer = new ShadowTransformer(mViewPager, mCardAdapter);
mFragmentCardShadowTransformer = new ShadowTransformer(mViewPager, mFragmentCardAdapter);

mViewPager.setAdapter(mCardAdapter);
mViewPager.setPageTransformer(false, mCardShadowTransformer);
mViewPager.setOffscreenPageLimit(3);
}

@Override
public void onClick(View view) {
if (!mShowingFragments) {
mButton.setText("Views");
mViewPager.setAdapter(mFragmentCardAdapter);
mViewPager.setPageTransformer(false, mFragmentCardShadowTransformer);
} else {
mButton.setText("Fragments");
mViewPager.setAdapter(mCardAdapter);
mViewPager.setPageTransformer(false, mCardShadowTransformer);
}

mShowingFragments = !mShowingFragments;
}

public static float dpToPixels(int dp, Context context) {
return dp * (context.getResources().getDisplayMetrics().density);
}

@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
mCardShadowTransformer.enableScaling(b);
mFragmentCardShadowTransformer.enableScaling(b);
}
}

Y con esto terminamos nuestro ejemplo de App Duolingo.

Crear Emulador AVD.(Aquí)


Ahora para ejecutar nuestro ejemplo crearemos un emulador.
Android Studio - ViewPager Cards inspirado en Duolingo

Descargar.




Espero el ejemplo haya sido claro con esto podemos hacer infinidad de opciones para mostrar algún tipo de contenido en nuestra aplicación basados en este ejemplo de la App de Duolingo. Espero sigan al tanto de nuestro contenido. Gracias.

No hay comentarios:

Publicar un comentario

x

Registrate!

Curso Android Español

Curso Kotlin Español

eBook Free Android Studio

Noticias y Eventos

¡Directamente a tu INBOX!

Le enviaremos nuestros recursos gratis. Para obtener nuestro contenido nuevo, únase a nuestra comunidad. No te molestaremos enviando información inútil. ¡No te pierdas ninguna actualización, mantente conectado! Recuerda verificar tu correo electronico.

Ingrese su dirección de correo electrónico:

Entregado por FeedBurner