android - viewpager - ¿Puedo usar el buscapersonas con vistas(no con fragmentos)?
slide android studio (6)
En base a las respuestas anteriores, hice la siguiente clase para lograr eso de la manera más adecuada y más clara (espero):
public class MyViewPagerAdapter extends PagerAdapter {
ArrayList<ViewGroup> views;
LayoutInflater inflater;
public MyViewPagerAdapter(ActionBarActivity ctx){
inflater = LayoutInflater.from(ctx);
//instantiate your views list
views = new ArrayList<ViewGroup>(5);
}
/**
* To be called by onStop
* Clean the memory
*/
public void release(){
views.clear();
views = null;
}
/**
* Return the number of views available.
*/
@Override
public int getCount() {
return 5;
}
/**
* Create the page for the given position. The adapter is responsible
* for adding the view to the container given here, although it only
* must ensure this is done by the time it returns from
* {@link #finishUpdate(ViewGroup)}.
*
* @param container The containing View in which the page will be shown.
* @param position The page position to be instantiated.
* @return Returns an Object representing the new page. This does not
* need to be a View, but can be some other container of
* the page. ,container
*/
public Object instantiateItem(ViewGroup container, int position) {
ViewGroup currentView;
Log.e("MyViewPagerAdapter", "instantiateItem for " + position);
if(views.size()>position&&views.get(position) != null){
Log.e("MyViewPagerAdapter",
"instantiateItem views.get(position) " +
views.get(position));
currentView = views.get(position);
}
else{
Log.e("MyViewPagerAdapter", "instantiateItem need to create the View");
int rootLayout = R.layout.view_screen;
currentView = (ViewGroup) inflater.inflate(rootLayout, container, false);
((TextView)currentView.findViewById(R.id.txvTitle)).setText("My Views " + position);
((TextView)currentView.findViewById(R.id.btnButton)).setText("Button");
((ImageView)currentView.findViewById(R.id.imvPicture)).setBackgroundColor(0xFF00FF00);
}
container.addView(currentView);
return currentView;
}
/**
* Remove a page for the given position. The adapter is responsible
* for removing the view from its container, although it only must ensure
* this is done by the time it returns from {@link #finishUpdate(ViewGroup)}.
*
* @param container The containing View from which the page will be removed.
* @param position The page position to be removed.
* @param object The same object that was returned by
* {@link #instantiateItem(View, int)}.
*/
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
/**
* Determines whether a page View is associated with a specific key object
* as returned by {@link #instantiateItem(ViewGroup, int)}. This method is
* required for a PagerAdapter to function properly.
*
* @param view Page View to check for association with <code>object</code>
* @param object Object to check for association with <code>view</code>
* @return true if <code>view</code> is associated with the key object <code>object</code>
*/
@Override
public boolean isViewFromObject(View view, Object object) {
return view==((View)object);
}
}
Y debes establecerlo en tu actividad:
public class ActivityWithViewsPaged extends ActionBarActivity {
/**
* The page Adapter: Manage the list of views (in fact here, its fragments)
* And send them to the ViewPager
*/
private MyViewPagerAdapter pagerAdapter;
/**
* The ViewPager is a ViewGroup that manage the swipe from left
* to right to left.
* Like a listView with a gesture listener...
*/
private ViewPager viewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_with_views);
// Find the viewPager
viewPager = (ViewPager) super.findViewById(R.id.viewpager);
// Instantiate the PageAdapter
pagerAdapter = new MyViewPagerAdapter(this);
// Affectation de l''adapter au ViewPager
viewPager.setAdapter(pagerAdapter);
viewPager.setClipToPadding(false);
viewPager.setPageMargin(12);
// Add animation when the page are swiped
// this instanciation only works with honeyComb and more
// if you want it all version use AnimatorProxy of the nineoldAndroid lib
//@see:http://stackoverflow.com/questions/15767729/backwards-compatible-pagetransformer
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
viewPager.setPageTransformer(true, new PageTransformer());
}
}
@Override
protected void onStop() {
super.onStop();
pagerAdapter.release();
}
Donde los archivos XML son obvios view_screen.xml:
<xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/screen"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/txvTitle"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:shadowColor="#FF00FF"
android:shadowDx="10"
android:shadowDy="10"
android:shadowRadius="5"
android:textSize="32dp"
android:textStyle="italic"
android:background="#FFFFF000"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFF00F0">
<TextView
android:id="@+id/txvLeft"
android:layout_width="wrap_content"
android:layout_gravity="left"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<TextView
android:id="@+id/txvRight"
android:layout_width="wrap_content"
android:layout_gravity="right"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"/>
</LinearLayout>
<Button
android:id="@+id/btnButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
<ImageView
android:id="@+id/imvPicture"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"/>
</LinearLayout>
Y ActivtyMain tiene el siguiente diseño:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:id="@+id/viewpager"
android:background="#FF00F0F0">
</android.support.v4.view.ViewPager>
Muchas gracias a Brian y Nicholas por su respuesta, espero agregar información más clara y algunas buenas prácticas para esta característica.
Estoy usando ViewPager
para ViewPager
entre Fragments
, pero ¿puedo usar ViewPager
para deslizar entre Views
diseño XML simple?
Este es mi Adapter
página para ViewPager que se usa para deslizar entre Fragmentos:
import java.util.List;
import com.app.name.fragments.TipsFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.view.ViewGroup;
public class PageAdapter extends FragmentPagerAdapter {
/**
*
*/
List<Fragment> fragments;
public PageAdapter(FragmentManager fm,List<Fragment> frags) {
super(fm);
fragments = frags;
}
@Override
public Fragment getItem(int arg0) {
// TODO Auto-generated method stub
return TipsFragment.newInstance(0, 0);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return 4;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
FragmentManager manager = ((Fragment) object).getFragmentManager();
FragmentTransaction trans = manager.beginTransaction();
trans.remove((Fragment) object);
trans.commit();
super.destroyItem(container, position, object);
}
}
Y este es mi fragmento de punta:
public class TipsFragment extends Fragment
{
public static TipsFragment newInstance(int image,int content)
{
TipsFragment fragment = new TipsFragment();
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.tip_layout, null);
return view;
}
}
¿Cómo puedo modificar mi código para que funcione con Views en lugar de Fragment?
Hemos construido una subclase muy simple de ViewPager
que usamos a veces.
/**
* View pager used for a finite, low number of pages, where there is no need for
* optimization.
*/
public class StaticViewPager extends ViewPager {
/**
* Initialize the view.
*
* @param context
* The application context.
*/
public StaticViewPager(final Context context) {
super(context);
}
/**
* Initialize the view.
*
* @param context
* The application context.
* @param attrs
* The requested attributes.
*/
public StaticViewPager(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// Make sure all are loaded at once
final int childrenCount = getChildCount();
setOffscreenPageLimit(childrenCount - 1);
// Attach the adapter
setAdapter(new PagerAdapter() {
@Override
public Object instantiateItem(final ViewGroup container, final int position) {
return container.getChildAt(position);
}
@Override
public boolean isViewFromObject(final View arg0, final Object arg1) {
return arg0 == arg1;
}
@Override
public int getCount() {
return childrenCount;
}
@Override
public void destroyItem(final View container, final int position, final Object object) {}
});
}
}
Esta clase no necesita un adaptador, ya que cargará las vistas desde el diseño. Para usarlo en sus proyectos, simplemente úselo en lugar de android.support.v4.view.ViewPager
.
Todas las cosas elegantes seguirán funcionando, pero no es necesario preocuparse por los adaptadores.
Me gustaría agregar mi solución aquí. Dado que no necesita usar fragmentos, puede crear un PagerAdapter
que PagerAdapter
views
lugar de fragments
a ViewPager
.
Extiende PagerAdapter
lugar de FragmentPagerAdapter
public class CustomPagerAdapter extends PagerAdapter {
private Context context;
public CustomPagerAdapter(Context context) {
super();
this.context = context;
}
@Override
public Object instantiateItem(ViewGroup collection, int position) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = null;
switch (position){
case 0:
view = MemoryView.getView(context, collection);
break;
case 1:
view = NetworkView.getView(context, collection);
break;
case 2:
view = CpuView.getView(context, collection);
break;
}
collection.addView(view);
return view;
}
@Override
public int getCount() {
return 3;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view==object;
}
@Override
public void destroyItem(ViewGroup collection, int position, Object view) {
collection.removeView((View) view);
}
}
Ahora necesita definir tres clases que devolverán las views
que se viewpager
en el viewpager
. Similar a CpuView
tendrá clases MemoryView
y NetworkView
. Cada uno de ellos inflará sus respectivos diseños.
public class CpuView {
public static View getView(Context context, ViewGroup collection) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context
.LAYOUT_INFLATER_SERVICE);
return inflater.inflate(R.layout.debugger_cpu_layout, collection, false);
}
}
Y finalmente un diseño que se inflará en cada una de las vistas
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:text="CPU"/>
</LinearLayout>
PD: El motivo por el que escribí esta respuesta es porque todas las soluciones proporcionadas aquí parecen funcionar bien, pero están inflando los diseños en la clase PagerAdapter. Para proyectos grandes se vuelve difícil mantener si hay muchos códigos relacionados con los diseños inflados. Ahora, en este ejemplo, todas las vistas tienen clases separadas y diseños separados. Entonces el proyecto puede mantenerse fácilmente.
Me gustaría detallar la respuesta de @Nicholas, puedes obtener las vistas por ID o si se agregan dinámicamente solo obtienes la vista dada su posición
class WizardPagerAdapter extends PagerAdapter {
public Object instantiateItem(View collection, int position) {
View v = pager.getChildAt(position);
return v;
}
@Override
public int getCount() {
return 3;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == ((View) arg1);
}
}
Usa este ejemplo
Puede usar un único diseño XML anidando las vistas secundarias.
<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.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/page_one"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:text="PAGE ONE IN"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#fff"
android:textSize="24dp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/page_two"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:text="PAGE TWO IN"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#fff"
android:textSize="24dp"/>
</LinearLayout>
</android.support.v4.view.ViewPager>
</LinearLayout>
PERO ... necesitas manejar esto con un adaptador también. Aquí devolvemos la identificación de la vista finalizada sin inflar ningún otro diseño.
class WizardPagerAdapter extends PagerAdapter {
public Object instantiateItem(ViewGroup collection, int position) {
int resId = 0;
switch (position) {
case 0:
resId = R.id.page_one;
break;
case 1:
resId = R.id.page_two;
break;
}
return findViewById(resId);
}
@Override
public int getCount() {
return 2;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override public void destroyItem(ViewGroup container, int position, Object object) {
// No super
}
}
// Establecer el adaptador ViewPager
WizardPagerAdapter adapter = new WizardPagerAdapter();
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(adapter);
getItem()
anular estos dos métodos en lugar de getItem()
:
@Override
public Object instantiateItem(ViewGroup collection, int position) {
View v = layoutInflater.inflate(...);
...
collection.addView(v,0);
return v;
}
@Override
public void destroyItem(ViewGroup collection, int position, Object view) {
collection.removeView((View) view);
}