studio setvisibility requestfocus layouts examples activity android android-layout android-canvas android-view android-gridview

requestfocus - setvisibility android studio



Pergamino infinito de objetos finitos. (3)

Esta solución se basa en el código fuente de @azizbekian ( gracias por un ejemplo interesante ). Fue muy divertido para mí encontrar algo parecido a lo que me pediste ( ambos al mismo tiempo ). Entonces, aquí está mi código modificado:

public class MainActivity extends AppCompatActivity { private static final int spanCount = 5; private static final int totalItemCount = 15; private GridLayoutManager gridLayoutManager; private RecyclerView recyclerView; private int orientation = 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = (RecyclerView) findViewById(R.id.recycler); recyclerView.setAdapter(new MyAdapter(totalItemCount)); // Shamelessly stolen from devunwired bit.ly/2yCqVIp recyclerView.addItemDecoration(new GridDividerDecoration(this)); gridLayoutManager = new GridLayoutManager(this, spanCount); recyclerView.setLayoutManager(gridLayoutManager); RecyclerView.OnScrollListener listener = new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recycler, int dx, int dy) { super.onScrolled(recycler, dx, dy); if (dx > 0) { orientation = LinearLayoutManager.HORIZONTAL; } else if (dx < 0) { orientation = LinearLayoutManager.VERTICAL; } else if (dy > 0) { orientation = LinearLayoutManager.VERTICAL; } else if (dy < 0) { orientation = LinearLayoutManager.HORIZONTAL; } recycler.post(new Runnable() { @Override public void run() { gridLayoutManager.setOrientation(orientation); recyclerView.setLayoutManager(gridLayoutManager); recyclerView.getAdapter().notifyDataSetChanged(); } }); } }; recyclerView.addOnScrollListener(listener); } static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> { private final int totalSizeOfItems; private boolean hasBeenSetup = false; MyAdapter(int totalSizeOfItems) { this.totalSizeOfItems = totalSizeOfItems; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); final int cellSize = parent.getMeasuredWidth() / spanCount; view.setMinimumWidth(cellSize); view.setMinimumHeight(cellSize); setupRecyclerHeightIfNeeded(parent, cellSize); return new MyViewHolder(view); } // We need to perform this operation once, not each time `onCreateViewHolder` is called private void setupRecyclerHeightIfNeeded(final View parent, int cellSize) { if (hasBeenSetup) return; hasBeenSetup = true; ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) parent.getLayoutParams(); int numOfRows = (int) (totalItemCount / (double) spanCount); params.height = numOfRows * cellSize + 100; // modified based on my phone height new Handler().post(new Runnable() { @Override public void run() { parent.requestLayout(); } }); } @Override public void onBindViewHolder(MyViewHolder holder, int pos) { int position = holder.getAdapterPosition() % totalSizeOfItems; holder.textView.setText(Integer.toString(position + 1)); } @Override public int getItemCount() { // this will result the list to be "infinite" return Integer.MAX_VALUE; } } static class MyViewHolder extends RecyclerView.ViewHolder { TextView textView; MyViewHolder(View itemView) { super(itemView); textView = (TextView) itemView; } } }

El diseño se desplaza hacia arriba para orientación vertical y se desplaza hacia la izquierda para horizontal. La salida está siguiendo ( perdón por la animación fea ):

Espero que te ayude.

Tengo un GridView que tiene elementos dentro de 5x50.

Necesito desplazarlos en todas direcciones y en lugar de detenerme cuando llegue al final, simplemente comience desde la parte superior / izquierda.

por ejemplo, desplazamiento de izquierda a derecha

antes de desplazamiento

1 2 3 4 5 6 7 8 9 10

despues desplaza hacia la derecha

5 1 2 3 4 10 6 7 8 9

y de arriba a abajo (o de abajo a arriba)

antes de desplazarse a la parte inferior

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

despues de desplazamiento

6 7 8 9 10 11 12 13 14 15 1 2 3 4 5

Intento que sea suave como el desplazamiento nativo de GridView .


Habiendo especificado la siguiente jerarquía de vistas en activity_main.xml :

<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout>

Y un elemento de lista básico: un TextView , dentro de item.xml :

<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center"/>

Luego en la actividad:

public class MainActivity extends AppCompatActivity { private static final int spanCount = 5; private static final int totalItemCount = 15; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RecyclerView recyclerView = findViewById(R.id.recycler); // Shamelessly stolen from devunwired bit.ly/2yCqVIp recyclerView.addItemDecoration(new GridDividerDecoration(this)); recyclerView.setLayoutManager(new GridLayoutManager(this, spanCount, LinearLayoutManager.VERTICAL, false)); recyclerView.setAdapter(new MyAdapter(totalItemCount)); } static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> { private final int totalSizeOfItems; private boolean hasBeenSetup = false; MyAdapter(int totalSizeOfItems) { this.totalSizeOfItems = totalSizeOfItems; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); final int cellSize = parent.getMeasuredWidth() / spanCount; view.setMinimumWidth(cellSize); view.setMinimumHeight(cellSize); setupRecyclerHeightIfNeeded(parent, cellSize); return new MyViewHolder(view); } // We need to perform this operation once, not each time `onCreateViewHolder` is called private void setupRecyclerHeightIfNeeded(View parent, int cellSize) { if (hasBeenSetup) return; hasBeenSetup = true; ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) parent.getLayoutParams(); int numOfRows = (int) (totalItemCount / (double) spanCount); params.height = numOfRows * cellSize; new Handler().post(parent::requestLayout); } @Override public void onBindViewHolder(MyViewHolder holder, int pos) { int position = holder.getAdapterPosition() % totalSizeOfItems; holder.textView.setText(Integer.toString(position + 1)); } @Override public int getItemCount() { // this will result the list to be "infinite" return Integer.MAX_VALUE; } } static class MyViewHolder extends RecyclerView.ViewHolder { TextView textView; MyViewHolder(View itemView) { super(itemView); textView = (TextView) itemView; } } }

En la salida obtendrá:

Cuidar el desplazamiento horizontal requeriría una pequeña cantidad de cambios:

  • La orientación de GridLayoutManager debe cambiarse a HORIZONTAL
  • Los adaptadores de ancho / altura apropiados del adaptador interior deben sustituirse

Aparte de eso, todo debería ser similar.


Here hay otra solución pero con un enfoque de lienzo.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/constraint_layout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <nice.fontaine.infinitescroll.CanvasView android:id="@+id/canvas_view" android:layout_width="match_parent" android:layout_height="match_parent"/> </android.support.constraint.ConstraintLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); CanvasView canvas = findViewById(R.id.canvas_view); String[][] labels = new String[][] { {"5", "8", "2"}, {"4", "7", "1"}, {"3", "6", "9"} }; int columns = 3; int rows = 3; canvas.with(labels, columns, rows); } }

CanvasView.java

public class CanvasView extends View { private final Panning panning; private final GridManager gridManager; private Rect bounds; private Point current = new Point(0, 0); private List<Overlay> overlays; public CanvasView(Context context, AttributeSet attrs) { super(context, attrs); bounds = new Rect(); panning = new Panning(); overlays = new ArrayList<>(); gridManager = new GridManager(this); init(); } public void with(String[][] labels, int columns, int rows) { gridManager.with(labels, columns, rows); } private void init() { ViewTreeObserver observer = getViewTreeObserver(); observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { int width = getWidth(); int height = getHeight(); bounds.set(0, 0, width, height); gridManager.generate(bounds); getViewTreeObserver().removeOnGlobalLayoutListener(this); } }); } @Override protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) { super.onSizeChanged(width, height, oldWidth, oldHeight); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); new Canvas(bitmap); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); bounds.offsetTo(-current.x, -current.y); gridManager.generate(bounds); canvas.translate(current.x, current.y); for (Overlay overlay : overlays) { if (overlay.intersects(bounds)) { overlay.onDraw(canvas); } } } @Override public boolean onTouchEvent(MotionEvent event) { current = panning.handle(event); invalidate(); return true; } public void addChild(Overlay overlay) { this.overlays.add(overlay); } }

GridManager.java

class GridManager { private final CanvasView canvas; private int columns; private int rows; private String[][] labels; private final Map<String, Overlay> cache; GridManager(CanvasView canvas) { this.canvas = canvas; cache = new HashMap<>(); } void with(String[][] labels, int columns, int rows) { this.columns = columns; this.rows = rows; this.labels = labels; } void generate(Rect bounds) { if (columns == 0 || rows == 0 || labels == null) return; int width = bounds.width(); int height = bounds.height(); int overlayWidth = width / columns; int overlayHeight = height / rows; int minX = mod(floor(bounds.left, overlayWidth), columns); int minY = mod(floor(bounds.top, overlayHeight), rows); int startX = floorToMod(bounds.left, overlayWidth); int startY = floorToMod(bounds.top, overlayHeight); for (int j = 0; j <= rows; j++) { for (int i = 0; i <= columns; i++) { String label = getLabel(minX, minY, i, j); int x = startX + i * overlayWidth; int y = startY + j * overlayHeight; String key = x + "_" + y; if (!cache.containsKey(key)) { Overlay overlay = new Overlay(label, x, y, overlayWidth, overlayHeight); cache.put(key, overlay); canvas.addChild(overlay); } } } } private String getLabel(int minX, int minY, int i, int j) { int m = mod(minX + i, columns); int n = mod(minY + j, rows); return labels[n][m]; } private int floor(double numerator, double denominator) { return (int) Math.floor(numerator / denominator); } private int floorToMod(int value, int modulo) { return value - mod(value, modulo); } private int mod(int value, int modulo) { return (value % modulo + modulo) % modulo; } }

Panning.java

class Panning { private Point start; private Point delta = new Point(0, 0); private Point cursor = new Point(0, 0); private boolean isFirst; Point handle(MotionEvent event) { final Point point = new Point((int) event.getX(), (int) event.getY()); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: press(); break; case MotionEvent.ACTION_MOVE: drag(point); break; } return new Point(cursor.x + delta.x, cursor.y + delta.y); } private void press() { isFirst = true; } private void drag(final Point point) { if (isFirst) { start = point; cursor.offset(delta.x, delta.y); isFirst = false; } delta.x = point.x - start.x; delta.y = point.y - start.y; } }

Overlay.java

class Overlay { private final String text; private final int x; private final int y; private final Paint paint; private final Rect bounds; private final Rect rect; private final Rect textRect; Overlay(String text, int x, int y, int width, int height) { this.text = text; this.bounds = new Rect(x, y, x + width, y + height); this.rect = new Rect(); this.textRect = new Rect(); paint = new Paint(); paint.setColor(Color.BLACK); setTextSize(text); this.x = x + width / 2 - textRect.width() / 2; this.y = y + height / 2 + textRect.height() / 2; } boolean intersects(Rect r) { rect.set(bounds.left, bounds.top, bounds.right, bounds.bottom); return rect.intersect(r.left, r.top, r.right, r.bottom); } void onDraw(Canvas canvas) { // rectangle paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); canvas.drawRect(bounds, paint); // centered text paint.setStrokeWidth(2); paint.setStyle(Paint.Style.FILL); canvas.drawText(text, x, y, paint); } private void setTextSize(String text) { final float testTextSize = 100f; paint.setTextSize(testTextSize); paint.getTextBounds(text, 0, text.length(), textRect); } }