recyclerView 布局网格项目未正确对齐
recyclerView layout grid items not aligning properly
我不太了解java,刚开始,所以我会很难理解答案。 emli5.
截图:
预期输出:
在 recyclerview(右)中,这些项目没有像我希望的那样对齐。
我希望每个单元格都具有固定大小和网格中可能的最大列数。
间距 b/w 每个单元格(垂直和水平)等于(左 space)除以(列数减一)。 [在开始、顶部、底部或结束处没有多余的 space]
代码如下:
package com.MyStickersWA.DogeStickers;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.format.Formatter;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.facebook.drawee.view.SimpleDraweeView;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.MobileAds;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@SuppressWarnings("ALL")
public class StickerPackDetailsActivity extends AddStickerPackActivity {
/**
* Do not change below values of below 3 lines as this is also used by WhatsApp
*/
public static final String EXTRA_STICKER_PACK_ID = "sticker_pack_id";
public static final String EXTRA_STICKER_PACK_AUTHORITY = "sticker_pack_authority";
public static final String EXTRA_STICKER_PACK_NAME = "sticker_pack_name";
public static final String EXTRA_STICKER_PACK_WEBSITE = "sticker_pack_website";
public static final String EXTRA_STICKER_PACK_EMAIL = "sticker_pack_email";
public static final String EXTRA_STICKER_PACK_PRIVACY_POLICY = "sticker_pack_privacy_policy";
public static final String EXTRA_STICKER_PACK_LICENSE_AGREEMENT = "sticker_pack_license_agreement";
public static final String EXTRA_STICKER_PACK_TRAY_ICON = "sticker_pack_tray_icon";
public static final String EXTRA_SHOW_UP_BUTTON = "show_up_button";
public static final String EXTRA_STICKER_PACK_DATA = "sticker_pack";
private RecyclerView recyclerView;
private GridLayoutManager layoutManager;
private StickerPreviewAdapter stickerPreviewAdapter;
private int numColumns;
private View addButton;
private View infoButton;
private View backButton;
private View alreadyAdded;
private StickerPack stickerPack;
private WhiteListCheckAsyncTask whiteListCheckAsyncTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sticker_pack_details);
AdView mAdView = findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder().build();
MobileAds.initialize(this, initializationStatus -> { });
mAdView.loadAd(adRequest);
boolean showUpButton = getIntent().getBooleanExtra(EXTRA_SHOW_UP_BUTTON, false);
stickerPack = getIntent().getParcelableExtra(EXTRA_STICKER_PACK_DATA);
TextView packNameTextView = findViewById(R.id.pack_name);
TextView packPublisherTextView = findViewById(R.id.author);
ImageView packTrayIcon = findViewById(R.id.tray_image);
TextView packSizeTextView = findViewById(R.id.pack_size);
TextView stickersQtyTextView = findViewById(R.id.stickers_qty);
TextView stickersAnimatedView = findViewById(R.id.stickers_animated);
ImageView stickersAnimatedImage = findViewById(R.id.sticker_pack_animation_indicator);
SimpleDraweeView expandedStickerView = findViewById(R.id.sticker_details_expanded_sticker);
addButton = findViewById(R.id.add_to_whatsapp_button);
infoButton = findViewById(R.id.action_info);
backButton = findViewById(R.id.action_back);
alreadyAdded = findViewById(R.id.already_added_button);
layoutManager = new GridLayoutManager(this, 1);
recyclerView = findViewById(R.id.sticker_list);
recyclerView.setLayoutManager(layoutManager);
recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(pageLayoutListener);
if (stickerPreviewAdapter == null) {
stickerPreviewAdapter = new StickerPreviewAdapter(getLayoutInflater(), R.drawable.sticker_error, getResources().getDimensionPixelSize(R.dimen.sticker_pack_details_image_size), getResources().getDimensionPixelSize(R.dimen.sticker_pack_details_image_padding), stickerPack, expandedStickerView);
recyclerView.setAdapter(stickerPreviewAdapter);
}
packNameTextView.setText(stickerPack.name);
packPublisherTextView.setText(stickerPack.publisher);
packTrayIcon.setImageURI(StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.trayImageFile));
packSizeTextView.setText(Formatter.formatShortFileSize(this, stickerPack.getTotalSize()));
stickersQtyTextView.setText(stickerPack.getTotalQty() + "");
addButton.setOnClickListener(v -> addStickerPackToWhatsApp(stickerPack.identifier, stickerPack.name));
infoButton.setOnClickListener(v -> onOptionsItemSelected());
backButton.setOnClickListener(v -> finish());
if (stickerPack.animatedStickerPack) {
Uri animatedIcon = Uri.parse("android.resource://" + getPackageName() + "/"+R.drawable.animated_indicator_vector);
stickersAnimatedImage.setImageURI(animatedIcon);
stickersAnimatedView.setText("Animated");
} else {
Uri animatedIcon = Uri.parse("android.resource://" + getPackageName() + "/"+R.drawable.static_indicator_vector);
stickersAnimatedImage.setImageURI(animatedIcon);
stickersAnimatedView.setText("Static");
}
}
private void launchInfoActivity(String publisherWebsite, String publisherEmail, String privacyPolicyWebsite, String licenseAgreementWebsite, String trayIconUriString) {
Intent intent = new Intent(StickerPackDetailsActivity.this, StickerPackInfoActivity.class);
intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_ID, stickerPack.identifier);
intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_WEBSITE, publisherWebsite);
intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_EMAIL, publisherEmail);
intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_PRIVACY_POLICY, privacyPolicyWebsite);
intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_LICENSE_AGREEMENT, licenseAgreementWebsite);
intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_TRAY_ICON, trayIconUriString);
startActivity(intent);
}
public boolean onOptionsItemSelected() {
if (stickerPack != null) {
Uri trayIconUri = StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.trayImageFile);
launchInfoActivity(stickerPack.publisherWebsite, stickerPack.publisherEmail, stickerPack.privacyPolicyWebsite, stickerPack.licenseAgreementWebsite, trayIconUri.toString());
return true;
}
return false;
}
private final ViewTreeObserver.OnGlobalLayoutListener pageLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int imgSize = recyclerView.getContext().getResources().getDimensionPixelSize(R.dimen.sticker_pack_details_image_size);
int recyclerViewWidth = recyclerView.getWidth();
int numColumns = recyclerViewWidth / imgSize;
int colSpacing = (recyclerViewWidth - (numColumns * imgSize)) / (numColumns - 1);
// int colSpacing = recyclerView.getWidth() - imgSize * numColumns;
setNumColumns(numColumns, colSpacing);
}
};
@SuppressLint("NotifyDataSetChanged")
private void setNumColumns(int numColumns, int colSpacing) {
if (this.numColumns != numColumns) {
// recyclerView.addItemDecoration(new GridSpacingItemDecoration(4, 2, 2));
layoutManager.setSpanCount(numColumns);
recyclerView.setLayoutManager(layoutManager);
this.numColumns = numColumns;
if (stickerPreviewAdapter != null) {
stickerPreviewAdapter.notifyDataSetChanged();
}
}
}
@Override
protected void onResume() {
super.onResume();
whiteListCheckAsyncTask = new WhiteListCheckAsyncTask(this);
whiteListCheckAsyncTask.execute(stickerPack);
}
@Override
protected void onPause() {
super.onPause();
if (whiteListCheckAsyncTask != null && !whiteListCheckAsyncTask.isCancelled()) {
whiteListCheckAsyncTask.cancel(true);
}
}
private void updateAddUI(Boolean isWhitelisted) {
if (isWhitelisted) {
addButton.setVisibility(View.GONE);
alreadyAdded.setVisibility(View.VISIBLE);
} else {
addButton.setVisibility(View.VISIBLE);
alreadyAdded.setVisibility(View.GONE);
}
}
static class WhiteListCheckAsyncTask extends AsyncTask<StickerPack, Void, Boolean> {
private final WeakReference<StickerPackDetailsActivity> stickerPackDetailsActivityWeakReference;
WhiteListCheckAsyncTask(StickerPackDetailsActivity stickerPackListActivity) {
this.stickerPackDetailsActivityWeakReference = new WeakReference<>(stickerPackListActivity);
}
@Override
protected final Boolean doInBackground(StickerPack... stickerPacks) {
StickerPack stickerPack = stickerPacks[0];
final StickerPackDetailsActivity stickerPackDetailsActivity = stickerPackDetailsActivityWeakReference.get();
if (stickerPackDetailsActivity == null) {
return false;
}
return WhitelistCheck.isWhitelisted(stickerPackDetailsActivity, stickerPack.identifier);
}
@Override
protected void onPostExecute(Boolean isWhitelisted) {
final StickerPackDetailsActivity stickerPackDetailsActivity = stickerPackDetailsActivityWeakReference.get();
if (stickerPackDetailsActivity != null) {
stickerPackDetailsActivity.updateAddUI(isWhitelisted);
}
}
}
}
/*
* Copyright (c) WhatsApp Inc. and its affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.MyStickersWA.DogeStickers;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
public class StickerPreviewAdapter extends RecyclerView.Adapter<StickerPreviewViewHolder> {
private static final float COLLAPSED_STICKER_PREVIEW_BACKGROUND_ALPHA = 1f;
private static final float EXPANDED_STICKER_PREVIEW_BACKGROUND_ALPHA = 0.2f;
@NonNull
private final StickerPack stickerPack;
private final int cellSize;
private final int cellLimit;
private final int cellPadding;
private final int errorResource;
private final SimpleDraweeView expandedStickerPreview;
private final LayoutInflater layoutInflater;
private RecyclerView recyclerView;
private View clickedStickerPreview;
float expandedViewLeftX;
float expandedViewTopY;
StickerPreviewAdapter(
@NonNull final LayoutInflater layoutInflater,
final int errorResource,
final int cellSize,
final int cellPadding,
@NonNull final StickerPack stickerPack,
final SimpleDraweeView expandedStickerView) {
this.cellSize = cellSize;
this.cellPadding = cellPadding;
this.cellLimit = 0;
this.layoutInflater = layoutInflater;
this.errorResource = errorResource;
this.stickerPack = stickerPack;
this.expandedStickerPreview = expandedStickerView;
}
@NonNull
@Override
public StickerPreviewViewHolder onCreateViewHolder(@NonNull final ViewGroup viewGroup, final int i) {
View itemView = layoutInflater.inflate(R.layout.sticker_image_item, viewGroup, false);
StickerPreviewViewHolder vh = new StickerPreviewViewHolder(itemView);
ViewGroup.LayoutParams layoutParams = vh.stickerPreviewView.getLayoutParams();
layoutParams.height = cellSize;
layoutParams.width = cellSize;
vh.stickerPreviewView.setLayoutParams(layoutParams);
vh.stickerPreviewView.setPadding(cellPadding, cellPadding, cellPadding, cellPadding);
return vh;
}
@Override
public void onBindViewHolder(@NonNull final StickerPreviewViewHolder stickerPreviewViewHolder, final int i) {
stickerPreviewViewHolder.stickerPreviewView.setImageResource(errorResource);
stickerPreviewViewHolder.stickerPreviewView.setImageURI(StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.getStickers().get(i).imageFileName));
stickerPreviewViewHolder.stickerPreviewView.setOnClickListener(v -> expandPreview(i, stickerPreviewViewHolder.stickerPreviewView));
}
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
this.recyclerView = recyclerView;
recyclerView.addOnScrollListener(hideExpandedViewScrollListener);
}
@Override
public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
recyclerView.removeOnScrollListener(hideExpandedViewScrollListener);
this.recyclerView = null;
}
private final RecyclerView.OnScrollListener hideExpandedViewScrollListener =
new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dx != 0 || dy != 0) {
hideExpandedStickerPreview();
}
}
};
private void positionExpandedStickerPreview(int selectedPosition) {
if (expandedStickerPreview != null) {
// Calculate the view's center (x, y), then use expandedStickerPreview's height and
// width to
// figure out what where to position it.
final ViewGroup.MarginLayoutParams recyclerViewLayoutParams =
((ViewGroup.MarginLayoutParams) recyclerView.getLayoutParams());
final int recyclerViewLeftMargin = recyclerViewLayoutParams.leftMargin;
final int recyclerViewRightMargin = recyclerViewLayoutParams.rightMargin;
final int recyclerViewWidth = recyclerView.getWidth();
final int recyclerViewHeight = recyclerView.getHeight();
final StickerPreviewViewHolder clickedViewHolder =
(StickerPreviewViewHolder)
recyclerView.findViewHolderForAdapterPosition(selectedPosition);
if (clickedViewHolder == null) {
hideExpandedStickerPreview();
return;
}
clickedStickerPreview = clickedViewHolder.itemView;
final float clickedViewCenterX =
clickedStickerPreview.getX()
+ recyclerViewLeftMargin
+ clickedStickerPreview.getWidth() / 2f;
final float clickedViewCenterY =
clickedStickerPreview.getY() + clickedStickerPreview.getHeight() / 2f;
expandedViewLeftX = clickedViewCenterX - expandedStickerPreview.getWidth() / 2f;
expandedViewTopY = clickedViewCenterY - expandedStickerPreview.getHeight() / 2f;
// If the new x or y positions are negative, anchor them to 0 to avoid clipping
// the left side of the device and the top of the recycler view.
expandedViewLeftX = Math.max(expandedViewLeftX, 0);
expandedViewTopY = Math.max(expandedViewTopY, 0);
// If the bottom or right sides are clipped, we need to move the top left positions
// so that those sides are no longer clipped.
final float adjustmentX =
Math.max(
expandedViewLeftX
+ expandedStickerPreview.getWidth()
- recyclerViewWidth
- recyclerViewRightMargin,
0);
final float adjustmentY =
Math.max(expandedViewTopY + expandedStickerPreview.getHeight() - recyclerViewHeight, 0);
expandedViewLeftX -= adjustmentX;
expandedViewTopY -= adjustmentY;
expandedStickerPreview.setX(expandedViewLeftX);
expandedStickerPreview.setY(expandedViewTopY);
}
}
private void expandPreview(int position, View clickedStickerPreview) {
if (isStickerPreviewExpanded()) {
hideExpandedStickerPreview();
return;
}
this.clickedStickerPreview = clickedStickerPreview;
if (expandedStickerPreview != null) {
positionExpandedStickerPreview(position);
final Uri stickerAssetUri = StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.getStickers().get(position).imageFileName);
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setUri(stickerAssetUri)
.setAutoPlayAnimations(true)
.build();
expandedStickerPreview.setImageResource(errorResource);
expandedStickerPreview.setController(controller);
expandedStickerPreview.setVisibility(View.VISIBLE);
recyclerView.setAlpha(EXPANDED_STICKER_PREVIEW_BACKGROUND_ALPHA);
expandedStickerPreview.setOnClickListener(v -> hideExpandedStickerPreview());
}
}
public void hideExpandedStickerPreview() {
if (isStickerPreviewExpanded() && expandedStickerPreview != null) {
clickedStickerPreview.setVisibility(View.VISIBLE);
expandedStickerPreview.setVisibility(View.INVISIBLE);
recyclerView.setAlpha(COLLAPSED_STICKER_PREVIEW_BACKGROUND_ALPHA);
}
}
private boolean isStickerPreviewExpanded() {
return expandedStickerPreview != null && expandedStickerPreview.getVisibility() == View.VISIBLE;
}
@Override
public int getItemCount() {
int numberOfPreviewImagesInPack;
numberOfPreviewImagesInPack = stickerPack.getStickers().size();
if (cellLimit > 0) {
return Math.min(numberOfPreviewImagesInPack, cellLimit);
}
return numberOfPreviewImagesInPack;
}
}
提前致谢
似乎每个项目都有正确的填充。
您应该在 RecyclerView 上使用 addItemDecoration
。
或者使用这个:https://github.com/grzegorzojdana/SpacingItemDecoration
您需要通过扩展RecyclerView.ItemDecoration
来创建自定义物品装饰。你可以这样做:
import android.graphics.Rect;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private final int numberOfColumns;
private final int spacing;
private final boolean addSpacingToPerimeter;
public GridSpacingItemDecoration(int numberOfColumns, int spacing, boolean addSpacingToPerimeter) {
this.numberOfColumns = numberOfColumns;
this.spacing = spacing;
this.addSpacingToPerimeter = addSpacingToPerimeter;
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, RecyclerView parent, @NonNull RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); // item position
int column = position % numberOfColumns; // item column
if (addSpacingToPerimeter) {
outRect.left = spacing - column * spacing / numberOfColumns;
outRect.right = (column + 1) * spacing / numberOfColumns;
if (position < numberOfColumns) { // top edge
outRect.top = spacing;
}
outRect.bottom = spacing; // item bottom
} else {
outRect.left = column * spacing / numberOfColumns;
outRect.right = spacing - (column + 1) * spacing / numberOfColumns;
if (position >= numberOfColumns) {
outRect.top = spacing; // item top
}
}
}
}
然后像这样使用它
int numberOfColumns = 3; // 3 columns
int spacing = 50; // 50px
boolean addSpacingToPerimeter = false;
recyclerView.addItemDecoration(new GridSpacingItemDecoration(numberOfColumns, spacing, addSpacingToPerimeter))
GridSpacingItemDecoration
class 将列数、间距(以像素为单位)和一个布尔值作为参数,该值指定是否要将间距也添加到列表的周边。这个布尔值如果设置为 true 将添加给定的间距作为边距,不仅在网格适配器的项目之间,而且在项目和整个 recyclerView 之间。
请记住间距以像素为单位。因此,如果您想改用 dp,可以使用
将 dp 转换为 px
Math.round(dpValue * getResources().getDisplayMetrics().density))
我不太了解java,刚开始,所以我会很难理解答案。 emli5.
截图:
预期输出:
在 recyclerview(右)中,这些项目没有像我希望的那样对齐。
我希望每个单元格都具有固定大小和网格中可能的最大列数。 间距 b/w 每个单元格(垂直和水平)等于(左 space)除以(列数减一)。 [在开始、顶部、底部或结束处没有多余的 space]
代码如下:
package com.MyStickersWA.DogeStickers;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.format.Formatter;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.facebook.drawee.view.SimpleDraweeView;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.MobileAds;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@SuppressWarnings("ALL")
public class StickerPackDetailsActivity extends AddStickerPackActivity {
/**
* Do not change below values of below 3 lines as this is also used by WhatsApp
*/
public static final String EXTRA_STICKER_PACK_ID = "sticker_pack_id";
public static final String EXTRA_STICKER_PACK_AUTHORITY = "sticker_pack_authority";
public static final String EXTRA_STICKER_PACK_NAME = "sticker_pack_name";
public static final String EXTRA_STICKER_PACK_WEBSITE = "sticker_pack_website";
public static final String EXTRA_STICKER_PACK_EMAIL = "sticker_pack_email";
public static final String EXTRA_STICKER_PACK_PRIVACY_POLICY = "sticker_pack_privacy_policy";
public static final String EXTRA_STICKER_PACK_LICENSE_AGREEMENT = "sticker_pack_license_agreement";
public static final String EXTRA_STICKER_PACK_TRAY_ICON = "sticker_pack_tray_icon";
public static final String EXTRA_SHOW_UP_BUTTON = "show_up_button";
public static final String EXTRA_STICKER_PACK_DATA = "sticker_pack";
private RecyclerView recyclerView;
private GridLayoutManager layoutManager;
private StickerPreviewAdapter stickerPreviewAdapter;
private int numColumns;
private View addButton;
private View infoButton;
private View backButton;
private View alreadyAdded;
private StickerPack stickerPack;
private WhiteListCheckAsyncTask whiteListCheckAsyncTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sticker_pack_details);
AdView mAdView = findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder().build();
MobileAds.initialize(this, initializationStatus -> { });
mAdView.loadAd(adRequest);
boolean showUpButton = getIntent().getBooleanExtra(EXTRA_SHOW_UP_BUTTON, false);
stickerPack = getIntent().getParcelableExtra(EXTRA_STICKER_PACK_DATA);
TextView packNameTextView = findViewById(R.id.pack_name);
TextView packPublisherTextView = findViewById(R.id.author);
ImageView packTrayIcon = findViewById(R.id.tray_image);
TextView packSizeTextView = findViewById(R.id.pack_size);
TextView stickersQtyTextView = findViewById(R.id.stickers_qty);
TextView stickersAnimatedView = findViewById(R.id.stickers_animated);
ImageView stickersAnimatedImage = findViewById(R.id.sticker_pack_animation_indicator);
SimpleDraweeView expandedStickerView = findViewById(R.id.sticker_details_expanded_sticker);
addButton = findViewById(R.id.add_to_whatsapp_button);
infoButton = findViewById(R.id.action_info);
backButton = findViewById(R.id.action_back);
alreadyAdded = findViewById(R.id.already_added_button);
layoutManager = new GridLayoutManager(this, 1);
recyclerView = findViewById(R.id.sticker_list);
recyclerView.setLayoutManager(layoutManager);
recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(pageLayoutListener);
if (stickerPreviewAdapter == null) {
stickerPreviewAdapter = new StickerPreviewAdapter(getLayoutInflater(), R.drawable.sticker_error, getResources().getDimensionPixelSize(R.dimen.sticker_pack_details_image_size), getResources().getDimensionPixelSize(R.dimen.sticker_pack_details_image_padding), stickerPack, expandedStickerView);
recyclerView.setAdapter(stickerPreviewAdapter);
}
packNameTextView.setText(stickerPack.name);
packPublisherTextView.setText(stickerPack.publisher);
packTrayIcon.setImageURI(StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.trayImageFile));
packSizeTextView.setText(Formatter.formatShortFileSize(this, stickerPack.getTotalSize()));
stickersQtyTextView.setText(stickerPack.getTotalQty() + "");
addButton.setOnClickListener(v -> addStickerPackToWhatsApp(stickerPack.identifier, stickerPack.name));
infoButton.setOnClickListener(v -> onOptionsItemSelected());
backButton.setOnClickListener(v -> finish());
if (stickerPack.animatedStickerPack) {
Uri animatedIcon = Uri.parse("android.resource://" + getPackageName() + "/"+R.drawable.animated_indicator_vector);
stickersAnimatedImage.setImageURI(animatedIcon);
stickersAnimatedView.setText("Animated");
} else {
Uri animatedIcon = Uri.parse("android.resource://" + getPackageName() + "/"+R.drawable.static_indicator_vector);
stickersAnimatedImage.setImageURI(animatedIcon);
stickersAnimatedView.setText("Static");
}
}
private void launchInfoActivity(String publisherWebsite, String publisherEmail, String privacyPolicyWebsite, String licenseAgreementWebsite, String trayIconUriString) {
Intent intent = new Intent(StickerPackDetailsActivity.this, StickerPackInfoActivity.class);
intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_ID, stickerPack.identifier);
intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_WEBSITE, publisherWebsite);
intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_EMAIL, publisherEmail);
intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_PRIVACY_POLICY, privacyPolicyWebsite);
intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_LICENSE_AGREEMENT, licenseAgreementWebsite);
intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_TRAY_ICON, trayIconUriString);
startActivity(intent);
}
public boolean onOptionsItemSelected() {
if (stickerPack != null) {
Uri trayIconUri = StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.trayImageFile);
launchInfoActivity(stickerPack.publisherWebsite, stickerPack.publisherEmail, stickerPack.privacyPolicyWebsite, stickerPack.licenseAgreementWebsite, trayIconUri.toString());
return true;
}
return false;
}
private final ViewTreeObserver.OnGlobalLayoutListener pageLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int imgSize = recyclerView.getContext().getResources().getDimensionPixelSize(R.dimen.sticker_pack_details_image_size);
int recyclerViewWidth = recyclerView.getWidth();
int numColumns = recyclerViewWidth / imgSize;
int colSpacing = (recyclerViewWidth - (numColumns * imgSize)) / (numColumns - 1);
// int colSpacing = recyclerView.getWidth() - imgSize * numColumns;
setNumColumns(numColumns, colSpacing);
}
};
@SuppressLint("NotifyDataSetChanged")
private void setNumColumns(int numColumns, int colSpacing) {
if (this.numColumns != numColumns) {
// recyclerView.addItemDecoration(new GridSpacingItemDecoration(4, 2, 2));
layoutManager.setSpanCount(numColumns);
recyclerView.setLayoutManager(layoutManager);
this.numColumns = numColumns;
if (stickerPreviewAdapter != null) {
stickerPreviewAdapter.notifyDataSetChanged();
}
}
}
@Override
protected void onResume() {
super.onResume();
whiteListCheckAsyncTask = new WhiteListCheckAsyncTask(this);
whiteListCheckAsyncTask.execute(stickerPack);
}
@Override
protected void onPause() {
super.onPause();
if (whiteListCheckAsyncTask != null && !whiteListCheckAsyncTask.isCancelled()) {
whiteListCheckAsyncTask.cancel(true);
}
}
private void updateAddUI(Boolean isWhitelisted) {
if (isWhitelisted) {
addButton.setVisibility(View.GONE);
alreadyAdded.setVisibility(View.VISIBLE);
} else {
addButton.setVisibility(View.VISIBLE);
alreadyAdded.setVisibility(View.GONE);
}
}
static class WhiteListCheckAsyncTask extends AsyncTask<StickerPack, Void, Boolean> {
private final WeakReference<StickerPackDetailsActivity> stickerPackDetailsActivityWeakReference;
WhiteListCheckAsyncTask(StickerPackDetailsActivity stickerPackListActivity) {
this.stickerPackDetailsActivityWeakReference = new WeakReference<>(stickerPackListActivity);
}
@Override
protected final Boolean doInBackground(StickerPack... stickerPacks) {
StickerPack stickerPack = stickerPacks[0];
final StickerPackDetailsActivity stickerPackDetailsActivity = stickerPackDetailsActivityWeakReference.get();
if (stickerPackDetailsActivity == null) {
return false;
}
return WhitelistCheck.isWhitelisted(stickerPackDetailsActivity, stickerPack.identifier);
}
@Override
protected void onPostExecute(Boolean isWhitelisted) {
final StickerPackDetailsActivity stickerPackDetailsActivity = stickerPackDetailsActivityWeakReference.get();
if (stickerPackDetailsActivity != null) {
stickerPackDetailsActivity.updateAddUI(isWhitelisted);
}
}
}
}
/*
* Copyright (c) WhatsApp Inc. and its affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.MyStickersWA.DogeStickers;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
public class StickerPreviewAdapter extends RecyclerView.Adapter<StickerPreviewViewHolder> {
private static final float COLLAPSED_STICKER_PREVIEW_BACKGROUND_ALPHA = 1f;
private static final float EXPANDED_STICKER_PREVIEW_BACKGROUND_ALPHA = 0.2f;
@NonNull
private final StickerPack stickerPack;
private final int cellSize;
private final int cellLimit;
private final int cellPadding;
private final int errorResource;
private final SimpleDraweeView expandedStickerPreview;
private final LayoutInflater layoutInflater;
private RecyclerView recyclerView;
private View clickedStickerPreview;
float expandedViewLeftX;
float expandedViewTopY;
StickerPreviewAdapter(
@NonNull final LayoutInflater layoutInflater,
final int errorResource,
final int cellSize,
final int cellPadding,
@NonNull final StickerPack stickerPack,
final SimpleDraweeView expandedStickerView) {
this.cellSize = cellSize;
this.cellPadding = cellPadding;
this.cellLimit = 0;
this.layoutInflater = layoutInflater;
this.errorResource = errorResource;
this.stickerPack = stickerPack;
this.expandedStickerPreview = expandedStickerView;
}
@NonNull
@Override
public StickerPreviewViewHolder onCreateViewHolder(@NonNull final ViewGroup viewGroup, final int i) {
View itemView = layoutInflater.inflate(R.layout.sticker_image_item, viewGroup, false);
StickerPreviewViewHolder vh = new StickerPreviewViewHolder(itemView);
ViewGroup.LayoutParams layoutParams = vh.stickerPreviewView.getLayoutParams();
layoutParams.height = cellSize;
layoutParams.width = cellSize;
vh.stickerPreviewView.setLayoutParams(layoutParams);
vh.stickerPreviewView.setPadding(cellPadding, cellPadding, cellPadding, cellPadding);
return vh;
}
@Override
public void onBindViewHolder(@NonNull final StickerPreviewViewHolder stickerPreviewViewHolder, final int i) {
stickerPreviewViewHolder.stickerPreviewView.setImageResource(errorResource);
stickerPreviewViewHolder.stickerPreviewView.setImageURI(StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.getStickers().get(i).imageFileName));
stickerPreviewViewHolder.stickerPreviewView.setOnClickListener(v -> expandPreview(i, stickerPreviewViewHolder.stickerPreviewView));
}
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
this.recyclerView = recyclerView;
recyclerView.addOnScrollListener(hideExpandedViewScrollListener);
}
@Override
public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
recyclerView.removeOnScrollListener(hideExpandedViewScrollListener);
this.recyclerView = null;
}
private final RecyclerView.OnScrollListener hideExpandedViewScrollListener =
new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dx != 0 || dy != 0) {
hideExpandedStickerPreview();
}
}
};
private void positionExpandedStickerPreview(int selectedPosition) {
if (expandedStickerPreview != null) {
// Calculate the view's center (x, y), then use expandedStickerPreview's height and
// width to
// figure out what where to position it.
final ViewGroup.MarginLayoutParams recyclerViewLayoutParams =
((ViewGroup.MarginLayoutParams) recyclerView.getLayoutParams());
final int recyclerViewLeftMargin = recyclerViewLayoutParams.leftMargin;
final int recyclerViewRightMargin = recyclerViewLayoutParams.rightMargin;
final int recyclerViewWidth = recyclerView.getWidth();
final int recyclerViewHeight = recyclerView.getHeight();
final StickerPreviewViewHolder clickedViewHolder =
(StickerPreviewViewHolder)
recyclerView.findViewHolderForAdapterPosition(selectedPosition);
if (clickedViewHolder == null) {
hideExpandedStickerPreview();
return;
}
clickedStickerPreview = clickedViewHolder.itemView;
final float clickedViewCenterX =
clickedStickerPreview.getX()
+ recyclerViewLeftMargin
+ clickedStickerPreview.getWidth() / 2f;
final float clickedViewCenterY =
clickedStickerPreview.getY() + clickedStickerPreview.getHeight() / 2f;
expandedViewLeftX = clickedViewCenterX - expandedStickerPreview.getWidth() / 2f;
expandedViewTopY = clickedViewCenterY - expandedStickerPreview.getHeight() / 2f;
// If the new x or y positions are negative, anchor them to 0 to avoid clipping
// the left side of the device and the top of the recycler view.
expandedViewLeftX = Math.max(expandedViewLeftX, 0);
expandedViewTopY = Math.max(expandedViewTopY, 0);
// If the bottom or right sides are clipped, we need to move the top left positions
// so that those sides are no longer clipped.
final float adjustmentX =
Math.max(
expandedViewLeftX
+ expandedStickerPreview.getWidth()
- recyclerViewWidth
- recyclerViewRightMargin,
0);
final float adjustmentY =
Math.max(expandedViewTopY + expandedStickerPreview.getHeight() - recyclerViewHeight, 0);
expandedViewLeftX -= adjustmentX;
expandedViewTopY -= adjustmentY;
expandedStickerPreview.setX(expandedViewLeftX);
expandedStickerPreview.setY(expandedViewTopY);
}
}
private void expandPreview(int position, View clickedStickerPreview) {
if (isStickerPreviewExpanded()) {
hideExpandedStickerPreview();
return;
}
this.clickedStickerPreview = clickedStickerPreview;
if (expandedStickerPreview != null) {
positionExpandedStickerPreview(position);
final Uri stickerAssetUri = StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.getStickers().get(position).imageFileName);
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setUri(stickerAssetUri)
.setAutoPlayAnimations(true)
.build();
expandedStickerPreview.setImageResource(errorResource);
expandedStickerPreview.setController(controller);
expandedStickerPreview.setVisibility(View.VISIBLE);
recyclerView.setAlpha(EXPANDED_STICKER_PREVIEW_BACKGROUND_ALPHA);
expandedStickerPreview.setOnClickListener(v -> hideExpandedStickerPreview());
}
}
public void hideExpandedStickerPreview() {
if (isStickerPreviewExpanded() && expandedStickerPreview != null) {
clickedStickerPreview.setVisibility(View.VISIBLE);
expandedStickerPreview.setVisibility(View.INVISIBLE);
recyclerView.setAlpha(COLLAPSED_STICKER_PREVIEW_BACKGROUND_ALPHA);
}
}
private boolean isStickerPreviewExpanded() {
return expandedStickerPreview != null && expandedStickerPreview.getVisibility() == View.VISIBLE;
}
@Override
public int getItemCount() {
int numberOfPreviewImagesInPack;
numberOfPreviewImagesInPack = stickerPack.getStickers().size();
if (cellLimit > 0) {
return Math.min(numberOfPreviewImagesInPack, cellLimit);
}
return numberOfPreviewImagesInPack;
}
}
提前致谢
似乎每个项目都有正确的填充。
您应该在 RecyclerView 上使用 addItemDecoration
。
或者使用这个:https://github.com/grzegorzojdana/SpacingItemDecoration
您需要通过扩展RecyclerView.ItemDecoration
来创建自定义物品装饰。你可以这样做:
import android.graphics.Rect;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private final int numberOfColumns;
private final int spacing;
private final boolean addSpacingToPerimeter;
public GridSpacingItemDecoration(int numberOfColumns, int spacing, boolean addSpacingToPerimeter) {
this.numberOfColumns = numberOfColumns;
this.spacing = spacing;
this.addSpacingToPerimeter = addSpacingToPerimeter;
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, RecyclerView parent, @NonNull RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); // item position
int column = position % numberOfColumns; // item column
if (addSpacingToPerimeter) {
outRect.left = spacing - column * spacing / numberOfColumns;
outRect.right = (column + 1) * spacing / numberOfColumns;
if (position < numberOfColumns) { // top edge
outRect.top = spacing;
}
outRect.bottom = spacing; // item bottom
} else {
outRect.left = column * spacing / numberOfColumns;
outRect.right = spacing - (column + 1) * spacing / numberOfColumns;
if (position >= numberOfColumns) {
outRect.top = spacing; // item top
}
}
}
}
然后像这样使用它
int numberOfColumns = 3; // 3 columns
int spacing = 50; // 50px
boolean addSpacingToPerimeter = false;
recyclerView.addItemDecoration(new GridSpacingItemDecoration(numberOfColumns, spacing, addSpacingToPerimeter))
GridSpacingItemDecoration
class 将列数、间距(以像素为单位)和一个布尔值作为参数,该值指定是否要将间距也添加到列表的周边。这个布尔值如果设置为 true 将添加给定的间距作为边距,不仅在网格适配器的项目之间,而且在项目和整个 recyclerView 之间。
请记住间距以像素为单位。因此,如果您想改用 dp,可以使用
将 dp 转换为 pxMath.round(dpValue * getResources().getDisplayMetrics().density))