Kotlin migration Featureadapter, ItemClickSupport (#1236)

This commit is contained in:
Birk Skyum
2023-06-14 00:45:51 +02:00
committed by GitHub
parent ca17d6bfe6
commit 269ae39a36
5 changed files with 233 additions and 282 deletions

View File

@@ -33,7 +33,7 @@ import java.util.*
*
*/
class FeatureOverviewActivity : AppCompatActivity() {
private var recyclerView: RecyclerView? = null
private lateinit var recyclerView: RecyclerView
private var sectionAdapter: FeatureSectionAdapter? = null
private var features: List<Feature>? = null
@@ -42,17 +42,20 @@ class FeatureOverviewActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_feature_overview)
recyclerView = findViewById<View>(R.id.recyclerView) as RecyclerView
recyclerView!!.layoutManager = LinearLayoutManager(this)
recyclerView!!.addOnItemTouchListener(SimpleOnItemTouchListener())
recyclerView!!.setHasFixedSize(true)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.addOnItemTouchListener(SimpleOnItemTouchListener())
recyclerView.setHasFixedSize(true)
ItemClickSupport.addTo(recyclerView)
.setOnItemClickListener { recyclerView: RecyclerView?, position: Int, view: View? ->
if (!sectionAdapter!!.isSectionHeaderPosition(position)) {
val itemPosition = sectionAdapter!!.getConvertedPosition(position)
val feature = features!![itemPosition]
startFeature(feature)
.setOnItemClickListener(object : ItemClickSupport.OnItemClickListener {
override fun onItemClicked(recyclerView: RecyclerView?, position: Int, view: View?) {
if (sectionAdapter!!.isSectionHeaderPosition(position).not()) {
val itemPosition = sectionAdapter!!.getConvertedPosition(position)
val feature = features!![itemPosition]
startFeature(feature)
}
}
}
})
if (savedInstanceState == null) {
loadFeatures()
} else {
@@ -164,7 +167,6 @@ class FeatureOverviewActivity : AppCompatActivity() {
onFeaturesLoaded(features)
}
}
companion object {
private const val KEY_STATE_FEATURES = "featureList"
}

View File

@@ -1,175 +0,0 @@
package org.maplibre.android.testapp.adapter;
import android.content.Context;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.maplibre.android.testapp.utils.FontCache;
import java.util.Arrays;
public class FeatureSectionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int SECTION_TYPE = 0;
private final Context context;
private final SparseArray<Section> sections;
private final RecyclerView.Adapter adapter;
@LayoutRes
private final int sectionRes;
@IdRes
private final int textRes;
private boolean valid = true;
public FeatureSectionAdapter(Context ctx, int sectionResourceId, int textResourceId,
RecyclerView.Adapter baseAdapter) {
context = ctx;
sectionRes = sectionResourceId;
textRes = textResourceId;
adapter = baseAdapter;
sections = new SparseArray<>();
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
valid = adapter.getItemCount() > 0;
notifyDataSetChanged();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
valid = adapter.getItemCount() > 0;
notifyItemRangeChanged(positionStart, itemCount);
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
valid = adapter.getItemCount() > 0;
notifyItemRangeInserted(positionStart, itemCount);
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
valid = adapter.getItemCount() > 0;
notifyItemRangeRemoved(positionStart, itemCount);
}
});
}
public static class SectionViewHolder extends RecyclerView.ViewHolder {
public TextView title;
public SectionViewHolder(@NonNull View view, @IdRes int textRes) {
super(view);
title = (TextView) view.findViewById(textRes);
title.setTypeface(FontCache.get("Roboto-Medium.ttf", view.getContext()));
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int typeView) {
if (typeView == SECTION_TYPE) {
final View view = LayoutInflater.from(context).inflate(sectionRes, parent, false);
return new SectionViewHolder(view, textRes);
} else {
return adapter.onCreateViewHolder(parent, typeView - 1);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder sectionViewHolder, int position) {
if (isSectionHeaderPosition(position)) {
String cleanTitle = sections.get(position).title.toString().replace("_", " ");
((SectionViewHolder) sectionViewHolder).title.setText(cleanTitle);
} else {
adapter.onBindViewHolder(sectionViewHolder, getConvertedPosition(position));
}
}
@Override
public int getItemViewType(int position) {
return isSectionHeaderPosition(position)
? SECTION_TYPE
: adapter.getItemViewType(getConvertedPosition(position)) + 1;
}
public static class Section {
int firstPosition;
int sectionedPosition;
CharSequence title;
public Section(int firstPosition, CharSequence title) {
this.firstPosition = firstPosition;
this.title = title;
}
public CharSequence getTitle() {
return title;
}
}
public void setSections(Section[] sections) {
this.sections.clear();
Arrays.sort(sections, (section, section1) -> (section.firstPosition == section1.firstPosition)
? 0
: ((section.firstPosition < section1.firstPosition) ? -1 : 1));
int offset = 0;
for (Section section : sections) {
section.sectionedPosition = section.firstPosition + offset;
this.sections.append(section.sectionedPosition, section);
++offset;
}
notifyDataSetChanged();
}
public int getConvertedPosition(int sectionedPosition) {
if (isSectionHeaderPosition(sectionedPosition)) {
return RecyclerView.NO_POSITION;
}
int offset = 0;
for (int i = 0; i < sections.size(); i++) {
if (sections.valueAt(i).sectionedPosition > sectionedPosition) {
break;
}
--offset;
}
return sectionedPosition + offset;
}
public boolean isSectionHeaderPosition(int position) {
return sections.get(position) != null;
}
@Override
public long getItemId(int position) {
return isSectionHeaderPosition(position)
? Integer.MAX_VALUE - sections.indexOfKey(position)
: adapter.getItemId(getConvertedPosition(position));
}
@Override
public int getItemCount() {
return (valid ? adapter.getItemCount() + sections.size() : 0);
}
}

View File

@@ -0,0 +1,142 @@
package org.maplibre.android.testapp.adapter
import android.content.Context
import android.util.SparseArray
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.annotation.IdRes
import androidx.annotation.LayoutRes
import androidx.recyclerview.widget.RecyclerView
import org.maplibre.android.testapp.utils.FontCache
import java.util.*
class FeatureSectionAdapter(
private val context: Context,
@param:LayoutRes private val sectionRes: Int,
@param:IdRes private val textRes: Int,
private val adapter: FeatureAdapter
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val sections = SparseArray<Section>()
private var valid = true
private val adapterDataObserver: RecyclerView.AdapterDataObserver =
object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
valid = adapter.itemCount > 0
notifyDataSetChanged()
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
valid = adapter.itemCount > 0
notifyItemRangeChanged(positionStart, itemCount)
}
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
valid = adapter.itemCount > 0
notifyItemRangeInserted(positionStart, itemCount)
}
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
valid = adapter.itemCount > 0
notifyItemRangeRemoved(positionStart, itemCount)
}
}
init {
adapter.registerAdapterDataObserver(adapterDataObserver)
}
override fun onCreateViewHolder(parent: ViewGroup, typeView: Int): RecyclerView.ViewHolder {
return if (typeView == SECTION_TYPE) {
val view = LayoutInflater.from(context).inflate(sectionRes, parent, false)
SectionViewHolder(view, textRes)
} else {
adapter.onCreateViewHolder(parent, typeView - 1)
}
}
override fun onBindViewHolder(sectionViewHolder: RecyclerView.ViewHolder, position: Int) {
if (isSectionHeaderPosition(position)) {
val cleanTitle = sections.get(position).title.toString().replace("_", " ")
(sectionViewHolder as SectionViewHolder).title.text = cleanTitle
} else {
adapter.onBindViewHolder(sectionViewHolder as FeatureAdapter.ViewHolder, getConvertedPosition(position))
}
}
override fun getItemViewType(position: Int): Int {
return if (isSectionHeaderPosition(position)) {
SECTION_TYPE
} else {
adapter.getItemViewType(getConvertedPosition(position)) + 1
}
}
override fun getItemId(position: Int): Long {
return if (isSectionHeaderPosition(position)) {
Integer.MAX_VALUE - sections.indexOfKey(position).toLong()
} else {
adapter.getItemId(getConvertedPosition(position))
}
}
override fun getItemCount(): Int {
return if (valid) adapter.itemCount + sections.size() else 0
}
fun setSections(sections: Array<Section>) {
this.sections.clear()
Arrays.sort(sections) { section, section1 ->
if (section.firstPosition == section1.firstPosition) {
0
} else if (section.firstPosition < section1.firstPosition) {
-1
} else {
1
}
}
for ((offset, section) in sections.withIndex()) {
section.sectionedPosition = section.firstPosition + offset
this.sections.append(section.sectionedPosition, section)
}
notifyDataSetChanged()
}
fun getConvertedPosition(sectionedPosition: Int): Int {
if (isSectionHeaderPosition(sectionedPosition)) {
return RecyclerView.NO_POSITION
}
var offset = 0
for (i in 0 until sections.size()) {
if (sections.valueAt(i).sectionedPosition > sectionedPosition) {
break
}
--offset
}
return sectionedPosition + offset
}
fun isSectionHeaderPosition(position: Int): Boolean {
return sections.get(position) != null
}
class SectionViewHolder(view: View, textRes: Int) :
RecyclerView.ViewHolder(view) {
val title: TextView = view.findViewById(textRes)
init {
title.typeface = FontCache["Roboto-Medium.ttf", view.context]
}
}
class Section(val firstPosition: Int, val title: CharSequence) {
var sectionedPosition = 0
}
companion object {
private const val SECTION_TYPE = 0
}
}

View File

@@ -1,96 +0,0 @@
package org.maplibre.android.testapp.utils;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
import org.maplibre.android.testapp.R;
public class ItemClickSupport {
private final RecyclerView recyclerView;
private OnItemClickListener onItemClickListener;
private OnItemLongClickListener onItemLongClickListener;
private View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
if (onItemClickListener != null) {
RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(view);
onItemClickListener.onItemClicked(recyclerView, holder.getAdapterPosition(), view);
}
}
};
private View.OnLongClickListener onLongClickListener = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if (onItemLongClickListener != null) {
RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(view);
return onItemLongClickListener.onItemLongClicked(recyclerView, holder.getAdapterPosition(), view);
}
return false;
}
};
private RecyclerView.OnChildAttachStateChangeListener attachListener
= new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(View view) {
if (onItemClickListener != null) {
view.setOnClickListener(onClickListener);
}
if (onItemLongClickListener != null) {
view.setOnLongClickListener(onLongClickListener);
}
}
@Override
public void onChildViewDetachedFromWindow(View view) {
}
};
private ItemClickSupport(RecyclerView recyclerView) {
this.recyclerView = recyclerView;
this.recyclerView.setTag(R.id.item_click_support, this);
this.recyclerView.addOnChildAttachStateChangeListener(attachListener);
}
public static ItemClickSupport addTo(RecyclerView view) {
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support == null) {
support = new ItemClickSupport(view);
}
return support;
}
public static ItemClickSupport removeFrom(RecyclerView view) {
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support != null) {
support.detach(view);
}
return support;
}
public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
onItemClickListener = listener;
return this;
}
public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
onItemLongClickListener = listener;
return this;
}
private void detach(RecyclerView view) {
view.removeOnChildAttachStateChangeListener(attachListener);
view.setTag(R.id.item_click_support, null);
}
public interface OnItemClickListener {
void onItemClicked(RecyclerView recyclerView, int position, View view);
}
public interface OnItemLongClickListener {
boolean onItemLongClicked(RecyclerView recyclerView, int position, View view);
}
}

View File

@@ -0,0 +1,78 @@
package org.maplibre.android.testapp.utils
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import org.maplibre.android.testapp.R
class ItemClickSupport private constructor(private val recyclerView: RecyclerView) {
private var onItemClickListener: OnItemClickListener? = null
private var onItemLongClickListener: OnItemLongClickListener? = null
private val onClickListener = View.OnClickListener { view ->
onItemClickListener?.let {
val holder = recyclerView.getChildViewHolder(view)
it.onItemClicked(recyclerView, holder.adapterPosition, view)
}
}
private val onLongClickListener = View.OnLongClickListener { view ->
onItemLongClickListener?.let {
val holder = recyclerView.getChildViewHolder(view)
it.onItemLongClicked(recyclerView, holder.adapterPosition, view)
}
false
}
private val attachListener = object : RecyclerView.OnChildAttachStateChangeListener {
override fun onChildViewAttachedToWindow(view: View) {
onItemClickListener?.let {
view.setOnClickListener(onClickListener)
}
onItemLongClickListener?.let {
view.setOnLongClickListener(onLongClickListener)
}
}
override fun onChildViewDetachedFromWindow(view: View) {}
}
fun setOnItemClickListener(listener: OnItemClickListener?): ItemClickSupport {
onItemClickListener = listener
return this
}
fun setOnItemLongClickListener(listener: OnItemLongClickListener?): ItemClickSupport {
onItemLongClickListener = listener
return this
}
private fun detach(view: RecyclerView) {
view.removeOnChildAttachStateChangeListener(attachListener)
view.setTag(R.id.item_click_support, null)
}
companion object {
fun addTo(view: RecyclerView): ItemClickSupport {
var support = view.getTag(R.id.item_click_support) as ItemClickSupport?
if (support == null) {
support = ItemClickSupport(view)
view.setTag(R.id.item_click_support, support)
view.addOnChildAttachStateChangeListener(support.attachListener)
}
return support
}
fun removeFrom(view: RecyclerView): ItemClickSupport? {
val support = view.getTag(R.id.item_click_support) as ItemClickSupport?
support?.let {
it.detach(view)
}
return support
}
}
interface OnItemClickListener {
fun onItemClicked(recyclerView: RecyclerView?, position: Int, view: View?)
}
interface OnItemLongClickListener {
fun onItemLongClicked(recyclerView: RecyclerView?, position: Int, view: View?): Boolean
}
}