Skip to content

Commit

Permalink
Merge pull request #11594 from t895/autofit-grid
Browse files Browse the repository at this point in the history
Android: Responsive autofit grid
  • Loading branch information
JosJuice committed Feb 25, 2023
2 parents f682225 + a049a0d commit 19e8569
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 51 deletions.
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: GPL-2.0-or-later

package org.dolphinemu.dolphinemu.layout

import android.content.Context
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.Recycler
import org.dolphinemu.dolphinemu.R

/**
* Cut down version of the solution provided here
* https://stackoverflow.com/questions/26666143/recyclerview-gridlayoutmanager-how-to-auto-detect-span-count
*/
class AutofitGridLayoutManager(
context: Context,
columnWidth: Int
) : GridLayoutManager(context, 1) {
private var columnWidth = 0
private var isColumnWidthChanged = true
private var lastWidth = 0
private var lastHeight = 0

init {
setColumnWidth(checkedColumnWidth(context, columnWidth))
}

private fun checkedColumnWidth(context: Context, columnWidth: Int): Int {
var newColumnWidth = columnWidth
if (newColumnWidth <= 0) {
newColumnWidth = context.resources.getDimensionPixelSize(R.dimen.spacing_xtralarge)
}
return newColumnWidth
}

fun setColumnWidth(newColumnWidth: Int) {
if (newColumnWidth > 0 && newColumnWidth != columnWidth) {
columnWidth = newColumnWidth
isColumnWidthChanged = true
}
}

override fun onLayoutChildren(recycler: Recycler, state: RecyclerView.State) {
val width = width
val height = height
if (columnWidth > 0 && width > 0 && height > 0 && (isColumnWidthChanged || lastWidth != width || lastHeight != height)) {
val totalSpace: Int = if (orientation == VERTICAL) {
width - paddingRight - paddingLeft
} else {
height - paddingTop - paddingBottom
}
val spanCount = 1.coerceAtLeast(totalSpace / columnWidth)
setSpanCount(spanCount)
isColumnWidthChanged = false
}
lastWidth = width
lastHeight = height
super.onLayoutChildren(recycler, state)
}
}
Expand Up @@ -6,29 +6,28 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import com.google.android.material.color.MaterialColors;

import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.adapters.GameAdapter;
import org.dolphinemu.dolphinemu.databinding.FragmentGridBinding;
import org.dolphinemu.dolphinemu.layout.AutofitGridLayoutManager;
import org.dolphinemu.dolphinemu.services.GameFileCacheManager;

public final class PlatformGamesFragment extends Fragment implements PlatformGamesView
{
private static final String ARG_PLATFORM = "platform";

private GameAdapter mAdapter;
private SwipeRefreshLayout mSwipeRefresh;
private SwipeRefreshLayout.OnRefreshListener mOnRefreshListener;

Expand Down Expand Up @@ -64,37 +63,12 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
public void onViewCreated(@NonNull View view, Bundle savedInstanceState)
{
mSwipeRefresh = mBinding.swipeRefresh;
mAdapter = new GameAdapter(requireActivity());

// Here we have to make sure the fragment is attached to an activity, wait for the layout
// to be drawn, and make sure it is drawn with a width > 0 before finding the correct
// span for our grid layout. Once drawn correctly, we can stop listening for layout changes.
if (isAdded())
{
view.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout()
{
if (mBinding.getRoot().getMeasuredWidth() == 0)
{
return;
}

int columns = mBinding.getRoot().getMeasuredWidth() /
requireContext().getResources().getDimensionPixelSize(R.dimen.card_width);
if (columns == 0)
{
columns = 1;
}
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), columns);
mBinding.gridGames.setLayoutManager(layoutManager);
mBinding.gridGames.setAdapter(mAdapter);
}
});
}
GameAdapter adapter = new GameAdapter(requireActivity());
adapter.setStateRestorationPolicy(
RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY);
mBinding.gridGames.setAdapter(adapter);
mBinding.gridGames.setLayoutManager(new AutofitGridLayoutManager(requireContext(),
getResources().getDimensionPixelSize(R.dimen.card_width)));

// Set theme color to the refresh animation's background
mSwipeRefresh.setProgressBackgroundColorSchemeColor(
Expand All @@ -118,12 +92,6 @@ public void onDestroyView()
mBinding = null;
}

@Override
public void refreshScreenshotAtPosition(int position)
{
mAdapter.notifyItemChanged(position);
}

@Override
public void onItemClick(String gameId)
{
Expand All @@ -133,17 +101,21 @@ public void onItemClick(String gameId)
@Override
public void showGames()
{
if (mAdapter != null)
if (mBinding == null)
return;

if (mBinding.gridGames.getAdapter() != null)
{
Platform platform = (Platform) getArguments().getSerializable(ARG_PLATFORM);
mAdapter.swapDataSet(GameFileCacheManager.getGameFilesForPlatform(platform));
((GameAdapter) mBinding.gridGames.getAdapter()).swapDataSet(
GameFileCacheManager.getGameFilesForPlatform(platform));
}
}

@Override
public void refetchMetadata()
{
mAdapter.refetchMetadata();
((GameAdapter) mBinding.gridGames.getAdapter()).refetchMetadata();
}

public void setOnRefreshListener(@Nullable SwipeRefreshLayout.OnRefreshListener listener)
Expand Down
Expand Up @@ -7,14 +7,6 @@
*/
public interface PlatformGamesView
{
/**
* Tell the view that a certain game's screenshot has been updated,
* and should be redrawn on-screen.
*
* @param position The index of the game that should be redrawn.
*/
void refreshScreenshotAtPosition(int position);

/**
* Pass a click event to the view's Presenter. Typically called from the
* view's list adapter.
Expand Down

0 comments on commit 19e8569

Please sign in to comment.