diff --git a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/ViewHolder.kt b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/ViewHolder.kt new file mode 100644 index 0000000000..e3273e33ce --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/ViewHolder.kt @@ -0,0 +1,6 @@ +package com.gh.gamecenter.adapter.viewholder + +import com.gh.base.BaseRecyclerViewHolder +import com.gh.gamecenter.databinding.SearchGameFooterBinding + +class SearchGameFooterViewHolder(val binding: SearchGameFooterBinding) : BaseRecyclerViewHolder(binding.root) \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameDetailFragment.java b/app/src/main/java/com/gh/gamecenter/search/SearchGameDetailFragment.java index 98d5bdaa92..fd0dea2b28 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameDetailFragment.java +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameDetailFragment.java @@ -2,12 +2,6 @@ package com.gh.gamecenter.search; import android.graphics.Rect; import android.os.Bundle; -import androidx.annotation.Nullable; -import androidx.fragment.app.FragmentActivity; -import androidx.core.content.ContextCompat; -import androidx.recyclerview.widget.DefaultItemAnimator; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; import android.text.SpannableString; import android.text.Spanned; import android.text.TextPaint; @@ -42,6 +36,13 @@ import org.greenrobot.eventbus.ThreadMode; import java.util.ArrayList; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import butterknife.BindView; import butterknife.OnClick; @@ -61,13 +62,16 @@ public class SearchGameDetailFragment extends BaseFragment implements OnRequestC View mSkipSuggestFunction; @BindView(R.id.reuse_nodata_skip_game) View mSkipSuggestGame; + @BindView(R.id.search_move_button) + TextView mMoveButton; + + private SearchGameDetailFragmentAdapter mAdapter; + private LinearLayoutManager mLayoutManager; + private ExposureListener mExposureListener; private String key; private String type; - private SearchGameDetailFragmentAdapter mAdapter; - private ExposureListener mExposureListener; - DataWatcher dataWatcher = new DataWatcher() { @Override public void onDataChanged(DownloadEntity downloadEntity) { @@ -98,10 +102,28 @@ public class SearchGameDetailFragment extends BaseFragment implements OnRequestC mSearchDetailRv.setHasFixedSize(true); mSearchDetailRv.addItemDecoration(new VerticalItemDecoration(getContext(), 8, true)); - mSearchDetailRv.setLayoutManager(new LinearLayoutManager(getActivity())); + mLayoutManager = new LinearLayoutManager(getActivity()); + mSearchDetailRv.setLayoutManager(mLayoutManager); ((DefaultItemAnimator) mSearchDetailRv.getItemAnimator()).setSupportsChangeAnimations(false); initAdapter(); + mSearchDetailRv.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + int position = mLayoutManager.findLastVisibleItemPosition(); + if (position == mAdapter.getItemCount() - 1) { + View view = mLayoutManager.findViewByPosition(position); + if (view != null && recyclerView.getBottom() - view.getBottom() > -DisplayUtils.dip2px(50)) { + mMoveButton.setVisibility(View.GONE); + } else { + mMoveButton.setVisibility(View.VISIBLE); + } + } else { + mMoveButton.setVisibility(View.VISIBLE); + } + } + }); + final View decorView = getActivity().getWindow().getDecorView(); decorView.getViewTreeObserver().addOnGlobalLayoutListener(() -> { Rect rect = new Rect(); @@ -120,7 +142,7 @@ public class SearchGameDetailFragment extends BaseFragment implements OnRequestC }); } - @OnClick({R.id.reuse_no_connection, R.id.reuse_nodata_skip_function, R.id.reuse_nodata_skip_game}) + @OnClick({R.id.reuse_no_connection, R.id.reuse_nodata_skip_function, R.id.reuse_nodata_skip_game, R.id.search_move_button}) public void onClick(View view) { switch (view.getId()) { case R.id.reuse_no_connection: @@ -136,6 +158,9 @@ public class SearchGameDetailFragment extends BaseFragment implements OnRequestC case R.id.reuse_nodata_skip_game: SuggestionActivity.startSuggestionActivity(getContext(), SuggestType.gameCollect, "求游戏:"); break; + case R.id.search_move_button: + mSearchDetailRv.smoothScrollToPosition(mAdapter.getItemCount() - 1); + break; } } @@ -186,12 +211,10 @@ public class SearchGameDetailFragment extends BaseFragment implements OnRequestC public void loadEmpty() { mSearchLoading.setVisibility(View.GONE); mSearchDetailRv.setVisibility(View.GONE); - SettingsEntity.AD ad = AdHelper.INSTANCE.getAd(AdHelper.LOCATION_SEARCH_EMPTY); - if (ad != null) { - showAd(ad); - } mSearchNoData.setVisibility(View.VISIBLE); mSearchNoConn.setVisibility(View.GONE); + + showAd(mSearchNoDataTv, false); } public void setParams(String key, String type) { @@ -199,8 +222,11 @@ public class SearchGameDetailFragment extends BaseFragment implements OnRequestC this.type = type; } - private void showAd(SettingsEntity.AD ad) { - SpannableString spannableString = new SpannableString(requireActivity().getString(R.string.search_empty_hint) + public void showAd(TextView view, boolean isSearchList) { + SettingsEntity.AD ad = AdHelper.INSTANCE.getAd(AdHelper.LOCATION_SEARCH_EMPTY); + if (ad == null) return; + String hint = requireActivity().getString(isSearchList ? R.string.search_empty_hint : R.string.search_bottom_hint); + SpannableString spannableString = new SpannableString(hint + "," + ad.getTitle()); ClickableSpan clickableSpan = new ClickableSpan() { @Override @@ -218,8 +244,8 @@ public class SearchGameDetailFragment extends BaseFragment implements OnRequestC String tempString = spannableString.toString(); int start = tempString.indexOf(ad.getTitle()); spannableString.setSpan(clickableSpan, start, spannableString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - mSearchNoDataTv.setMovementMethod(LinkMovementMethod.getInstance()); - mSearchNoDataTv.setText(spannableString); + view.setMovementMethod(LinkMovementMethod.getInstance()); + view.setText(spannableString); } //下载被删除事件 diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameDetailFragmentAdapter.java b/app/src/main/java/com/gh/gamecenter/search/SearchGameDetailFragmentAdapter.java index 47138c0a95..89498278af 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameDetailFragmentAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameDetailFragmentAdapter.java @@ -1,16 +1,13 @@ package com.gh.gamecenter.search; -import androidx.collection.ArrayMap; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; import android.text.TextUtils; import android.util.SparseArray; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.gh.base.OnRequestCallBackListener; import com.gh.common.constant.Config; +import com.gh.common.constant.ItemViewType; import com.gh.common.exposure.ExposureEvent; import com.gh.common.exposure.ExposureSource; import com.gh.common.exposure.ExposureType; @@ -23,14 +20,18 @@ import com.gh.download.DownloadManager; import com.gh.gamecenter.GameDetailActivity; import com.gh.gamecenter.R; import com.gh.gamecenter.SearchActivity; +import com.gh.gamecenter.SuggestionActivity; import com.gh.gamecenter.adapter.viewholder.GameViewHolder; +import com.gh.gamecenter.adapter.viewholder.SearchGameFooterViewHolder; import com.gh.gamecenter.databinding.GameItemBinding; +import com.gh.gamecenter.databinding.SearchGameFooterBinding; import com.gh.gamecenter.entity.ApkEntity; import com.gh.gamecenter.entity.GameEntity; import com.gh.gamecenter.eventbus.EBSearch; import com.gh.gamecenter.game.GameItemViewHolder; import com.gh.gamecenter.retrofit.Response; import com.gh.gamecenter.retrofit.RetrofitManager; +import com.gh.gamecenter.suggest.SuggestType; import com.lightgame.adapter.BaseRecyclerAdapter; import com.lightgame.utils.Util_System_Keyboard; @@ -40,12 +41,16 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +import androidx.collection.ArrayMap; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView.ViewHolder; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; import retrofit2.HttpException; class SearchGameDetailFragmentAdapter extends BaseRecyclerAdapter implements IExposable { + private SearchGameDetailFragment mFragment; private OnRequestCallBackListener listener; private List gameList; @@ -59,6 +64,7 @@ class SearchGameDetailFragmentAdapter extends BaseRecyclerAdapter im SearchGameDetailFragmentAdapter(SearchGameDetailFragment fragment, String key, String type, String entrance) { super(fragment.getContext()); + this.mFragment = fragment; this.listener = fragment; this.entrance = entrance; @@ -136,20 +142,39 @@ class SearchGameDetailFragmentAdapter extends BaseRecyclerAdapter im } @Override - public GameItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { - View itemView = LayoutInflater.from(viewGroup.getContext()).inflate( - R.layout.game_item, viewGroup, false); - return new GameItemViewHolder(GameItemBinding.bind(itemView)); + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { + if (viewType == ItemViewType.ITEM_BODY) { + View itemView = mLayoutInflater.inflate(R.layout.game_item, viewGroup, false); + return new GameItemViewHolder(GameItemBinding.bind(itemView)); + } else { + View view = mLayoutInflater.inflate(R.layout.search_game_footer, viewGroup, false); + return new SearchGameFooterViewHolder(SearchGameFooterBinding.bind(view)); + } } @Override public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) { - GameItemViewHolder gameItemViewHolder = (GameItemViewHolder) holder; - final GameItemBinding binding = gameItemViewHolder.getBinding(); - final GameEntity gameEntity = gameList.get(position); + if (holder instanceof GameItemViewHolder) { + bindGameItem((GameItemViewHolder) holder); + } else if (holder instanceof SearchGameFooterViewHolder) { + bindFooterItem((SearchGameFooterViewHolder) holder); + } + } + + private void bindFooterItem(SearchGameFooterViewHolder holder) { + holder.getBinding().skipFunction.setOnClickListener(v -> + SuggestionActivity.startSuggestionActivity(mContext, SuggestType.functionSuggest, "求功能:")); + holder.getBinding().skipGame.setOnClickListener(v -> + SuggestionActivity.startSuggestionActivity(mContext, SuggestType.gameCollect, "求游戏:")); + mFragment.showAd(holder.getBinding().hintText, true); + } + + private void bindGameItem(GameItemViewHolder holder) { + final GameItemBinding binding = holder.getBinding(); + final GameEntity gameEntity = gameList.get(holder.getAdapterPosition()); binding.setGame(gameEntity); binding.setSubjectTag("type"); - gameItemViewHolder.initServerType(gameEntity); + holder.initServerType(gameEntity); binding.executePendingBindings(); ArrayList exposureSources = new ArrayList<>(); @@ -160,7 +185,7 @@ class SearchGameDetailFragmentAdapter extends BaseRecyclerAdapter im exposureSources, null, ExposureType.EXPOSURE); - exposureEventArray.put(position, exposureEvent); + exposureEventArray.put(holder.getAdapterPosition(), exposureEvent); binding.getRoot().setOnClickListener(v -> { if (searchMap.get(gameEntity.getId()) == null) { @@ -191,7 +216,7 @@ class SearchGameDetailFragmentAdapter extends BaseRecyclerAdapter im StringUtils.buildString(entrance, "+(搜索-列表[", key, "=", type, "=", String.valueOf(holder.getAdapterPosition() + 1), "])"), "搜索-列表:" + gameEntity.getName(), - exposureEvent); + exposureEvent); } else { DownloadDialog.getInstance(mContext).showPopupWindow(v, gameEntity, StringUtils.buildString(entrance, "+(搜索-列表[", key, "=", type, "=", @@ -204,9 +229,18 @@ class SearchGameDetailFragmentAdapter extends BaseRecyclerAdapter im DownloadItemUtils.updateItem(mContext, gameEntity, new GameViewHolder(binding), true); } + @Override + public int getItemViewType(int position) { + if (position == getItemCount() - 1) { + return ItemViewType.ITEM_FOOTER; + } else { + return ItemViewType.ITEM_BODY; + } + } + @Override public int getItemCount() { - return gameList.size(); + return gameList.size() + 1; } public ArrayMap> getLocationMap() { diff --git a/app/src/main/res/drawable/search_move_button.xml b/app/src/main/res/drawable/search_move_button.xml new file mode 100644 index 0000000000..767a4c347d --- /dev/null +++ b/app/src/main/res/drawable/search_move_button.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fm_search.xml b/app/src/main/res/layout/fm_search.xml index 695bcee1ae..d72ed277f5 100644 --- a/app/src/main/res/layout/fm_search.xml +++ b/app/src/main/res/layout/fm_search.xml @@ -47,7 +47,7 @@ android:gravity = "center" android:orientation = "vertical" android:visibility = "gone" - tools:visibility = "visible"> + tools:visibility = "visible" > + \ No newline at end of file diff --git a/app/src/main/res/layout/search_game_footer.xml b/app/src/main/res/layout/search_game_footer.xml new file mode 100644 index 0000000000..c9889f2564 --- /dev/null +++ b/app/src/main/res/layout/search_game_footer.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index db30fdb668..d48d1a618e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -388,6 +388,7 @@ 工具箱 告诉小编 搜索结果为空 + 找不到想要的游戏? 置顶 热门