Статьи

Будьте ленивым, но продуктивным Android-разработчиком, часть 6: ступенчатый GridView

Добро пожаловать в шестую часть серии «Будьте ленивым, но продуктивным разработчиком Android». Если вы ленивый разработчик Android и ищете библиотеку и готовый код  :) для отображения Staggered GridView в вашем приложении для Android, то эта статья будет вам интересна!

Эта серия до сих пор:

  • Часть 1 : Мы посмотрели на RoboGuice, библиотеку внедрения зависимостей, с помощью которой мы можем уменьшить код базовой платы, сэкономить время и добиться повышения производительности при разработке приложений для Android.
  • Часть 2 : Мы видели и изучали Genymotion, который является эмулятором скорости ракеты и супер-быстрым эмулятором по сравнению с нативным эмулятором. И мы можем использовать Genymotion при разработке приложений и можем быстро тестировать приложения, что позволяет добиться производительности.
  • Часть 3 : Мы поняли и изучили библиотеки JSON Parsing (GSON и Jackson), с помощью которых мы можем повысить производительность приложений, уменьшить шаблонный код и тем самым оптимизировать производительность.
  • Часть 4. Мы поговорили об интерфейсе пользователя карты и изучили библиотеку карт, а также создали базовую карту и демонстрацию простого списка карт.
  • Часть 5 : Мы говорили о библиотеках для асинхронной загрузки изображений, мы также сравнивали некоторые библиотеки, такие как Picasso, volley, Universal Image loader.

В этой части

В этом выпуске мы поговорим о Staggered GridView и о том, как сделать приложение классным, включив его в наше приложение для Android. Доступно 2-3 библиотеки с открытым исходным кодом, которые мы можем использовать для отображения Staggered GridView в нашем приложении.

В шахматном порядке GridView

Разнесенный GridView — это не что иное, как GridView, имеющий несколько столбцов со строками разных размеров. Возможно, вы использовали приложение Pinterest, Expedia или Etsy для Android, где вы заметили этот вид Staggered GridView. Если вы еще не использовали его, просто посмотрите на приведенные ниже снимки, чтобы получить точное представление.

в шахматном порядке gridview в Android

Я могу быть уверен, что вы либо начали задумываться о программировании, но ленивым разработчикам Android не нужно писать ни единой строчки кода, поскольку уже есть 2-3 великолепных библиотеки (с открытым исходным кодом), любой из которых мы можем интегрировать и получить такой же потрясающий интерфейс.

Разнесенные библиотеки GridView

  1. В шахматном порядке GridView от Etsy
  2. Пораженная GridView Мориси Войтович

Давайте посмотрим на шахматное изображение Etsy в шахматном порядке, так как оно более популярно и широко используется (1572 звезды и 272 вилки) в приложении для Android, по сравнению с шахматным сетчатым представлением мэриси (750 звезд 411 вилка).

Etsy в шахматном порядке GridView в Android

Согласно описанию библиотеки, они разработали это настраиваемое представление из-за требований к своему Android-приложению Etsy, которые не были выполнены ни одной из существующих библиотек Android. Эта библиотека предоставляет возможность иметь различное количество столбцов в альбомной и портретной ориентации, синхронизировать положение сетки при изменении ориентации и поддержку верхних и нижних колонтитулов.

Они разработали этот настраиваемый Staggered GridView, расширив класс AbsListView, и он также поддерживает AbsListView.OnScrollListener.

Характеристики

  • Настраиваемое количество столбцов для книжной и альбомной ориентации.
  • Синхронизировать положение строки по изменению ориентации.
  • Настраиваемая маржа товара.
  • Поддержка верхних и нижних колонтитулов.
  • Внутренний отступ, который не влияет на верхний и нижний колонтитулы.

Пошаговое отображение сетки Etsy не поддерживает событие длинного нажатия на Item и рисование селектора, в то время как смещенное отображение сетки Maurycy поддерживает событие длинного нажатия на элемент.

Пример: Etsy в шахматном порядке GridView

Вывод
Техноталкативная шахматная сетка в Android

Шаг 1. Загрузка / включение библиотеки в проект.
Эта библиотека в настоящее время настроена на сборку только с помощью  Gradle , поэтому, если вы используете любую из Android Studio, вы можете напрямую включить библиотеку в качестве зависимости от вашей сборки. Если вы все еще используете сборку Eclipse / Ant, вам придется выполнить дополнительные действия.

Для Android Studio:

?
repositories {
mavenCentral()
}
dependencies {
compile 'com.etsy.android.grid:library:x.x.x' // read below comment
}

// см.  CHANGELOG.md

Для сборки Eclipse / Ant: загрузите  этот библиотечный проект  и импортируйте его в Eclipse как существующий проект.

Шаг 2: Возьмите StaggeredGridView внутри макета

?
<com.etsy.android.grid.StaggeredGridView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/grid_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:item_margin="8dp"
app:column_count="@integer/grid_column_count" />
<!-- define grid_column_count as '2' inside integers.xml file -->

Шаг 3. Определение пользовательского макета строки для
пользовательской строки StaggeredGridView должно включать DynamicHeightImageView или DynamicHeightTextView.

?
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/panel_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
android:orientation="horizontal" >
<com.etsy.android.grid.util.DynamicHeightImageView
android:id="@+id/imgView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
</FrameLayout>

Шаг 4. Определите пользовательский класс адаптера.
Определите пользовательский класс адаптера для отображения динамического отображения высоты изображения в шахматном виде сетки. Я использовал универсальную библиотеку загрузчика изображений для асинхронной загрузки изображений.

?
package com.technotalkative.staggeredgriddemo;
import java.util.ArrayList;
import java.util.Random;
import android.content.Context;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import com.etsy.android.grid.util.DynamicHeightImageView;
import com.nostra13.universalimageloader.core.ImageLoader;
public class SampleAdapter extends ArrayAdapter<String> {
private static final String TAG = "SampleAdapter";
private final LayoutInflater mLayoutInflater;
private final Random mRandom;
private static final SparseArray<Double> sPositionHeightRatios = new SparseArray<Double>();
public SampleAdapter(Context context, int textViewResourceId,
ArrayList<String> objects) {
super(context, textViewResourceId, objects);
this.mLayoutInflater = LayoutInflater.from(context);
this.mRandom = new Random();
}
@Override
public View getView(final int position, View convertView,
final ViewGroup parent) {
ViewHolder vh;
if (convertView == null) {
convertView = mLayoutInflater.inflate(R.layout.row_grid_item,
parent, false);
vh = new ViewHolder();
vh.imgView = (DynamicHeightImageView) convertView
.findViewById(R.id.imgView);
convertView.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
double positionHeight = getPositionRatio(position);
vh.imgView.setHeightRatio(positionHeight);
ImageLoader.getInstance().displayImage(getItem(position), vh.imgView);
return convertView;
}
static class ViewHolder {
DynamicHeightImageView imgView;
}
private double getPositionRatio(final int position) {
double ratio = sPositionHeightRatios.get(position, 0.0);
// if not yet done generate and stash the columns height
// in our real world scenario this will be determined by
// some match based on the known height and width of the image
// and maybe a helpful way to get the column height!
if (ratio == 0) {
ratio = getRandomHeightRatio();
sPositionHeightRatios.append(position, ratio);
Log.d(TAG, "getPositionRatio:" + position + " ratio:" + ratio);
}
return ratio;
}
private double getRandomHeightRatio() {
return (mRandom.nextDouble() / 2.0) + 1.0; // height will be 1.0 - 1.5
// the width
}
}

Шаг 5. Установите определенный пользовательский адаптер в StaggeredGridView.

?
package com.technotalkative.staggeredgriddemo;
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.Toast;
import com.etsy.android.grid.StaggeredGridView;
public class StaggeredGridActivity extends Activity implements AbsListView.OnScrollListener, AbsListView.OnItemClickListener {
private static final String TAG = "StaggeredGridActivity";
public static final String SAVED_DATA_KEY = "SAVED_DATA";
private StaggeredGridView mGridView;
private boolean mHasRequestedMore;
private SampleAdapter mAdapter;
private ArrayList<String> mData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sgv);
setTitle("TechnoTalkative - SGV Demo");
mGridView = (StaggeredGridView) findViewById(R.id.grid_view);
mAdapter = new SampleAdapter(this,android.R.layout.simple_list_item_1, generateData());
// do we have saved data?
if (savedInstanceState != null) {
mData = savedInstanceState.getStringArrayList(SAVED_DATA_KEY);
}
if (mData == null) {
mData = generateData();
}
for (String data : mData) {
mAdapter.add(data);
}
mGridView.setAdapter(mAdapter);
mGridView.setOnScrollListener(this);
mGridView.setOnItemClickListener(this);
}
@Override
protected void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putStringArrayList(SAVED_DATA_KEY, mData);
}
@Override
public void onScrollStateChanged(final AbsListView view, final int scrollState) {
Log.d(TAG, "onScrollStateChanged:" + scrollState);
}
@Override
public void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount, final int totalItemCount) {
Log.d(TAG, "onScroll firstVisibleItem:" + firstVisibleItem +
" visibleItemCount:" + visibleItemCount +
" totalItemCount:" + totalItemCount);
// our handling
if (!mHasRequestedMore) {
int lastInScreen = firstVisibleItem + visibleItemCount;
if (lastInScreen >= totalItemCount) {
Log.d(TAG, "onScroll lastInScreen - so load more");
mHasRequestedMore = true;
onLoadMoreItems();
}
}
}
private void onLoadMoreItems() {
final ArrayList<String> sampleData = generateData();
for (String data : sampleData) {
mAdapter.add(data);
}
// stash all the data in our backing store
mData.addAll(sampleData);
// notify the adapter that we can update now
mAdapter.notifyDataSetChanged();
mHasRequestedMore = false;
}
private ArrayList<String> generateData() {
ArrayList<String> listData = new ArrayList<String>();
listData.add("http://i62.tinypic.com/2iitkhx.jpg");
listData.add("http://i61.tinypic.com/w0omeb.jpg");
listData.add("http://i60.tinypic.com/w9iu1d.jpg");
listData.add("http://i60.tinypic.com/iw6kh2.jpg");
listData.add("http://i57.tinypic.com/ru08c8.jpg");
listData.add("http://i60.tinypic.com/k12r10.jpg");
listData.add("http://i58.tinypic.com/2e3daug.jpg");
listData.add("http://i59.tinypic.com/2igznfr.jpg");
return listData;
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Toast.makeText(this, "Item Clicked: " + position, Toast.LENGTH_SHORT).show();
}
}

Скачать исходный код

Вы можете скачать исходный код приведенных выше примеров  здесь . Надеюсь, вам понравилась эта часть серии «Ленивый разработчик Android: будьте продуктивным». До следующей части продолжайте изучать обе библиотеки в шахматном порядке и попробуйте настроить их больше. Наслаждайтесь!