Skip to content
This repository has been archived by the owner on Oct 28, 2023. It is now read-only.

BindableLayoutBuilder add hasStableIds(),viewItemId() #18

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 29 additions & 1 deletion library/src/main/java/io/nlopez/smartadapters/SmartAdapter.java
@@ -1,6 +1,7 @@
package io.nlopez.smartadapters;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.v7.widget.RecyclerView;
import android.widget.AbsListView;
Expand All @@ -24,6 +25,10 @@ private SmartAdapter() {

}

public interface ConstructorRecyclerAdapter {
RecyclerMultiAdapter constructor(Mapper mapper, List listItems, BindableLayoutBuilder builder);
}

/**
* Include the object list that is going to be represented in our collection view.
*
Expand Down Expand Up @@ -129,6 +134,18 @@ public RecyclerMultiAdapter recyclerAdapter() {
return response;
}

/**
* Returns the instantiated adapter for RecyclerView
*
* @param constructorRecyclerAdapter
* @return adapter based on {@code RecyclerView.Adapter}
*/
public RecyclerMultiAdapter recyclerAdapter(@NonNull ConstructorRecyclerAdapter constructorRecyclerAdapter) {
RecyclerMultiAdapter response = constructorRecyclerAdapter.constructor(mapper, elements, builder);
response.setViewEventListener(listener);
return response;
}

/**
* Assigns the created adapter to the given {@code AbsListView} inherited widget (ListView, GridView).
*
Expand All @@ -149,8 +166,19 @@ public MultiAdapter into(@NonNull AbsListView widget) {
* @return assigned adapter
*/
public RecyclerMultiAdapter into(@NonNull RecyclerView recyclerView) {
return into(recyclerView,null);
}

/**
* Assigns the created adapter to the given {@code RecyclerView}.
*
* @param recyclerView instance of RecyclerView
* @param constructorRecyclerAdapter
* @return assigned adapter
*/
public RecyclerMultiAdapter into(@NonNull RecyclerView recyclerView,@Nullable ConstructorRecyclerAdapter constructorRecyclerAdapter) {
validateMapper();
RecyclerMultiAdapter adapter = recyclerAdapter();
RecyclerMultiAdapter adapter = constructorRecyclerAdapter == null ? recyclerAdapter() : recyclerAdapter(constructorRecyclerAdapter);
recyclerView.setAdapter(adapter);
return adapter;
}
Expand Down
Expand Up @@ -3,16 +3,15 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import java.util.List;

import io.nlopez.smartadapters.builders.BindableLayoutBuilder;
import io.nlopez.smartadapters.builders.DefaultBindableLayoutBuilder;
import io.nlopez.smartadapters.utils.Mapper;
import io.nlopez.smartadapters.utils.ThreadHelper;
import io.nlopez.smartadapters.utils.ViewEventListener;
import io.nlopez.smartadapters.views.BindableLayout;

import java.util.List;

/**
* Adapter for {@code AbsListView} based widgets
*/
Expand Down Expand Up @@ -131,7 +130,16 @@ public Object getItem(int position) {

@Override
public long getItemId(int position) {
return position;
Object object = listItems.get(position);
return builder.viewItemId(object, position, mapper);
}

@Override
public boolean hasStableIds() {
if(builder.hasStableIds())
return builder.hasStableIds();
else
return super.hasStableIds();
}

@Override
Expand Down
Expand Up @@ -3,10 +3,6 @@
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

import io.nlopez.smartadapters.builders.BindableLayoutBuilder;
import io.nlopez.smartadapters.builders.DefaultBindableLayoutBuilder;
import io.nlopez.smartadapters.utils.Mapper;
Expand All @@ -15,6 +11,9 @@
import io.nlopez.smartadapters.views.BindableLayout;
import io.nlopez.smartadapters.views.BindableViewHolder;

import java.util.ArrayList;
import java.util.List;

/**
* Adapter for {@code RecyclerView} based widgets
*/
Expand All @@ -40,6 +39,7 @@ public RecyclerMultiAdapter(Mapper mapper, List listItems, BindableLayoutBuilder
this.builder = builder;
}
this.itemClassArray = new ArrayList<>(mapper.objectClasses());
this.setHasStableIds(this.builder.hasStableIds());
}

@Override
Expand Down Expand Up @@ -136,7 +136,8 @@ public int getItemViewType(int position) {

@Override
public long getItemId(int position) {
return position;
Object object = listItems.get(position);
return builder.viewItemId(object, position, mapper);
}

@Override
Expand Down
Expand Up @@ -13,4 +13,8 @@ public interface BindableLayoutBuilder<T> {
Class<? extends BindableLayout> viewType(@NonNull T item, int position, @NonNull Mapper mapper);

boolean allowsMultimapping();

boolean hasStableIds();

long viewItemId(@NonNull T item, int position, @NonNull Mapper mapper);
}
Expand Up @@ -4,14 +4,13 @@
import android.support.annotation.NonNull;
import android.view.View;
import android.view.ViewGroup;

import java.lang.reflect.Constructor;
import java.util.List;

import io.nlopez.smartadapters.utils.Mapper;
import io.nlopez.smartadapters.utils.Reflections;
import io.nlopez.smartadapters.views.BindableLayout;

import java.lang.reflect.Constructor;
import java.util.List;

/**
* Basic layout builder for most of the cases. It handles the reflection caching so the impact
* done by it is very little.
Expand Down Expand Up @@ -51,4 +50,14 @@ public Class<? extends BindableLayout> viewType(@NonNull Object item, int positi
@Override public boolean allowsMultimapping() {
return false;
}

@Override
public boolean hasStableIds() {
return false;
}

@Override
public long viewItemId(@NonNull Object item, int position, @NonNull Mapper mapper) {
return position;
}
}
@@ -1,5 +1,6 @@
package io.nlopez.smartadapters.builders;

import android.support.annotation.NonNull;
import android.view.View;
import android.view.ViewGroup;

Expand All @@ -15,6 +16,7 @@
import io.nlopez.smartadapters.mocks.MockModel2;
import io.nlopez.smartadapters.utils.Mapper;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -58,4 +60,25 @@ public void test_crash_if_unknown_view_class() {
int viewType = Mapper.viewTypeFromViewClass(builder.viewType(new Object(), 0, mapper));
View bindableLayout = builder.build(parent, viewType, null, mapper);
}

@Test
public void test_build_view_item_id() {
DefaultBindableLayoutBuilder builder = new DefaultBindableLayoutBuilder(){
@Override
public boolean hasStableIds() {
return true;
}

@Override
public long viewItemId(@NonNull Object item, int position, @NonNull Mapper mapper) {
return 100 + position;
}
};

long itemId = builder.viewItemId(mockModel, 0, mapper);

assertEquals(itemId,100);
assertTrue(builder.hasStableIds());
}

}
2 changes: 2 additions & 0 deletions sample/build.gradle
Expand Up @@ -20,6 +20,8 @@ dependencies {
compile 'com.android.support:appcompat-v7:23.1.0'
compile 'com.jakewharton:butterknife:6.1.0'
compile 'com.squareup.picasso:picasso:2.5.2'
//https://github.com/timehop/sticky-headers-recyclerview
compile 'com.timehop.stickyheadersrecyclerview:library:0.4.3@aar'
compile project(':library')
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
Expand Down
1 change: 1 addition & 0 deletions sample/src/main/AndroidManifest.xml
Expand Up @@ -30,5 +30,6 @@
<activity android:name=".SingleRecyclerViewActivity" />
<activity android:name=".MultiRecyclerViewActivity" />
<activity android:name=".MultiRecyclerViewCustomBuilderActivity" />
<activity android:name=".StickyHeadersRecyclerViewActivity" />
</application>
</manifest>
Expand Up @@ -42,4 +42,9 @@ void launchMultiRecyclerViewCustomBuilder() {
startActivity(new Intent(this, MultiRecyclerViewCustomBuilderActivity.class));
}

@OnClick(R.id.sticky_headers_recyclerview_custom_builder_button)
void launchStickyHeadersRecyclerViewCustomBuilder() {
startActivity(new Intent(this, StickyHeadersRecyclerViewActivity.class));
}

}
Expand Up @@ -10,6 +10,7 @@
import butterknife.ButterKnife;
import butterknife.InjectView;
import io.nlopez.smartadapters.SmartAdapter;
import io.nlopez.smartadapters.adapters.RecyclerMultiAdapter;
import io.nlopez.smartadapters.sample.model.User;
import io.nlopez.smartadapters.sample.util.DataGenerator;
import io.nlopez.smartadapters.sample.view.UserView;
Expand All @@ -31,7 +32,8 @@ public void onCreate(Bundle bundle) {
private void initView() {
List<User> userList = DataGenerator.generateUsers(100);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
SmartAdapter.items(userList).map(User.class, UserView.class).into(recyclerView);
RecyclerMultiAdapter adapter = SmartAdapter.items(userList).map(User.class, UserView.class).into(recyclerView);

}

}
@@ -0,0 +1,130 @@
package io.nlopez.smartadapters.sample;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import com.timehop.stickyheadersrecyclerview.StickyRecyclerHeadersAdapter;
import com.timehop.stickyheadersrecyclerview.StickyRecyclerHeadersDecoration;
import com.timehop.stickyheadersrecyclerview.StickyRecyclerHeadersTouchListener;

import java.security.SecureRandom;
import java.util.List;

import butterknife.ButterKnife;
import butterknife.InjectView;
import io.nlopez.smartadapters.SmartAdapter;
import io.nlopez.smartadapters.adapters.RecyclerMultiAdapter;
import io.nlopez.smartadapters.builders.BindableLayoutBuilder;
import io.nlopez.smartadapters.sample.model.User;
import io.nlopez.smartadapters.sample.util.DataGenerator;
import io.nlopez.smartadapters.sample.view.UserView;
import io.nlopez.smartadapters.utils.Mapper;

public class StickyHeadersRecyclerViewActivity extends Activity {

@InjectView(R.id.recycler_view)
RecyclerView recyclerView;

@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_recyclerview);

ButterKnife.inject(this);
initView();
}

private void initView() {
List<User> userList = DataGenerator.generateUsers(100);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
MyRecyclerMultiAdapter adapter = (MyRecyclerMultiAdapter) SmartAdapter.items(userList).map(User.class, UserView.class)
.recyclerAdapter(new SmartAdapter.ConstructorRecyclerAdapter() {
@Override
public RecyclerMultiAdapter constructor(Mapper mapper, List listItems, BindableLayoutBuilder builder) {

return new MyRecyclerMultiAdapter(mapper,listItems,builder);
}
});

recyclerView.setAdapter(adapter);

// Add the sticky headers decoration
final StickyRecyclerHeadersDecoration headersDecor = new StickyRecyclerHeadersDecoration(adapter);
recyclerView.addItemDecoration(headersDecor);

// Add decoration for dividers between list items
// recyclerView.addItemDecoration(new DividerDecoration(this));

// Add touch listeners
StickyRecyclerHeadersTouchListener touchListener =
new StickyRecyclerHeadersTouchListener(recyclerView, headersDecor);
touchListener.setOnHeaderClickListener(
new StickyRecyclerHeadersTouchListener.OnHeaderClickListener() {
@Override
public void onHeaderClick(View header, int position, long headerId) {
Toast.makeText(StickyHeadersRecyclerViewActivity.this, "Header position: " + position + ", id: " + headerId,
Toast.LENGTH_SHORT).show();
}
});
recyclerView.addOnItemTouchListener(touchListener);

adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
headersDecor.invalidateHeaders();
}
});


}

public class MyRecyclerMultiAdapter extends RecyclerMultiAdapter implements StickyRecyclerHeadersAdapter<RecyclerView.ViewHolder> {

public MyRecyclerMultiAdapter(Mapper mapper, List listItems, BindableLayoutBuilder builder) {
super(mapper, listItems, builder);
}

@Override
public long getHeaderId(int position) {
if (position == 0) {
return -1;
} else {
return 'A';
}
}

@Override
public RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup parent) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.view_header, parent, false);
return new RecyclerView.ViewHolder(view) {
};
}

@Override
public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder, int position) {
TextView textView = (TextView) holder.itemView;
textView.setText(String.valueOf('A'));
holder.itemView.setBackgroundColor(getRandomColor());
}

private int getRandomColor() {
SecureRandom rgen = new SecureRandom();
return Color.HSVToColor(150, new float[]{
rgen.nextInt(359), 1, 1
});
}

}



}