Skip to content
This repository has been archived by the owner on Mar 16, 2024. It is now read-only.

Commit

Permalink
Merge branch 'feature-selection'
Browse files Browse the repository at this point in the history
  • Loading branch information
ShamylZakariya committed Jul 29, 2016
2 parents aa96bb6 + 75c2d5b commit 95cc246
Show file tree
Hide file tree
Showing 23 changed files with 1,231 additions and 43 deletions.
9 changes: 8 additions & 1 deletion NOTES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
#BUGS
#SELECTION

I think that section collapse and section/item/footer selection state should probably be treated as "data source" get methods. Without setters! The default implementations should return false. If you want selection or section collapse, you should implement it as part of your data source.

This means all my selection code is garbage! GARBAGE!

... DOES IT?


#TESTING:
- need to ensure this works fine for adapters which don't have footer views and which don't have header views (!!!)
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@
android:value=".ui.MainActivity"/>
</activity>

<activity
android:name=".ui.SelectionDemo"
android:theme="@style/AppTheme.NoActionBar"
android:label="@string/title_selection_demo"
android:launchMode="singleTop"
android:parentActivityName=".ui.MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ui.MainActivity"/>
</activity>

</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
package org.zakariya.stickyheadersapp.adapters;

import android.annotation.SuppressLint;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import org.zakariya.stickyheaders.SectioningAdapter;
import org.zakariya.stickyheadersapp.R;

import java.util.ArrayList;

/**
* Created by shamyl on 7/26/16.
*/
public class SelectionDemoAdapter extends SectioningAdapter {

private static final String TAG = "SelectionDemoAdapter";

private class Section {
int index;
String header;
String footer;
ArrayList<String> items = new ArrayList<>();
}

public class ItemViewHolder extends SectioningAdapter.ItemViewHolder {
TextView textView;
TextView adapterPositionTextView;

public ItemViewHolder(View itemView, boolean showAdapterPosition) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.textView);
adapterPositionTextView = (TextView) itemView.findViewById(R.id.adapterPositionTextView);

if (showAdapterPosition) {
adapterPositionTextView.setVisibility(View.GONE);
}
}
}

public class HeaderViewHolder extends SectioningAdapter.HeaderViewHolder {
TextView textView;
TextView adapterPositionTextView;

public HeaderViewHolder(View itemView, boolean showAdapterPosition) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.textView);
adapterPositionTextView = (TextView) itemView.findViewById(R.id.adapterPositionTextView);

if (showAdapterPosition) {
adapterPositionTextView.setVisibility(View.INVISIBLE);
}
}
}

public class FooterViewHolder extends SectioningAdapter.FooterViewHolder {
TextView textView;
TextView adapterPositionTextView;

public FooterViewHolder(View itemView, boolean showAdapterPosition) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.textView);
adapterPositionTextView = (TextView) itemView.findViewById(R.id.adapterPositionTextView);

if (showAdapterPosition) {
adapterPositionTextView.setVisibility(View.GONE);
}
}
}

ArrayList<Section> sections = new ArrayList<>();
boolean showAdapterPositions;


public SelectionDemoAdapter(int numSections, int numItemsPerSection, boolean showAdapterPositions) {
this.showAdapterPositions = showAdapterPositions;

for (int i = 0; i < numSections; i++) {
appendSection(i, numItemsPerSection);
}
}

void appendSection(int index, int itemCount) {
Section section = new Section();
section.index = index;
section.header = Integer.toString(index);
section.footer = "End of section " + Integer.toString(index);

for (int j = 0; j < itemCount; j++) {
section.items.add(index + "/" + j);
}

sections.add(section);
}

void duplicateSection(int sectionIndex) {
Section srcSection = sections.get(sectionIndex);
Section cloneSection = new Section();
cloneSection.index = srcSection.index;
cloneSection.header = srcSection.header + " (clone)";
cloneSection.footer = srcSection.footer + " (clone)";
cloneSection.items = new ArrayList<>(srcSection.items);
sections.add(sectionIndex + 1, cloneSection);

notifySectionInserted(sectionIndex + 1);
}

void duplicateItem(int sectionIndex, int itemIndex) {
Section section = sections.get(sectionIndex);
if (section != null) {
String src = section.items.get(itemIndex);
section.items.add(itemIndex + 1, src + " (copy)");

notifySectionItemInserted(sectionIndex, itemIndex + 1);
}
}

public void deleteSelection() {

traverseSelection(new SelectionVisitor() {
@Override
public void onVisitSelectedSection(int sectionIndex) {
Log.d(TAG, "onVisitSelectedSection() called with: " + "sectionIndex = [" + sectionIndex + "]");
sections.remove(sectionIndex);
notifySectionRemoved(sectionIndex);
}

@Override
public void onVisitSelectedSectionItem(int sectionIndex, int itemIndex) {
Log.d(TAG, "onVisitSelectedSectionItem() called with: " + "sectionIndex = [" + sectionIndex + "], itemIndex = [" + itemIndex + "]");
Section section = sections.get(sectionIndex);
if (section != null) {
section.items.remove(itemIndex);
notifySectionItemRemoved(sectionIndex, itemIndex);
}
}

@Override
public void onVisitSelectedFooter(int sectionIndex) {
Log.d(TAG, "onVisitSelectedFooter() called with: " + "sectionIndex = [" + sectionIndex + "]");
Section section = sections.get(sectionIndex);
if (section != null) {
section.footer = null;
notifySectionFooterRemoved(sectionIndex);
}
}
});

// clear selection without notification - because that would fight the deletion animations triggered above
clearSelection(false);

}

public void duplicateSelection() {

traverseSelection(new SelectionVisitor() {
@Override
public void onVisitSelectedSection(int sectionIndex) {
Log.d(TAG, "onVisitSelectedSection() called with: " + "sectionIndex = [" + sectionIndex + "]");
duplicateSection(sectionIndex);
}

@Override
public void onVisitSelectedSectionItem(int sectionIndex, int itemIndex) {
Log.d(TAG, "onVisitSelectedSectionItem() called with: " + "sectionIndex = [" + sectionIndex + "], itemIndex = [" + itemIndex + "]");
duplicateItem(sectionIndex, itemIndex);
}

@Override
public void onVisitSelectedFooter(int sectionIndex) {
// no-op
}
});

clearSelection();
}

@Override
public int getNumberOfSections() {
return sections.size();
}

@Override
public int getNumberOfItemsInSection(int sectionIndex) {
return sections.get(sectionIndex).items.size();
}

@Override
public boolean doesSectionHaveHeader(int sectionIndex) {
return !TextUtils.isEmpty(sections.get(sectionIndex).header);
}

@Override
public boolean doesSectionHaveFooter(int sectionIndex) {
return !TextUtils.isEmpty(sections.get(sectionIndex).footer);
}

@Override
public ItemViewHolder onCreateItemViewHolder(ViewGroup parent, int itemType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View v = inflater.inflate(R.layout.list_item_selectable_item, parent, false);
return new ItemViewHolder(v, showAdapterPositions);
}

@Override
public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent, int headerType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View v = inflater.inflate(R.layout.list_item_selectable_header, parent, false);
return new HeaderViewHolder(v, showAdapterPositions);
}

@Override
public FooterViewHolder onCreateFooterViewHolder(ViewGroup parent, int footerType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View v = inflater.inflate(R.layout.list_item_selectable_footer, parent, false);
return new FooterViewHolder(v, showAdapterPositions);
}

@SuppressLint("SetTextI18n")
@Override
public void onBindItemViewHolder(SectioningAdapter.ItemViewHolder viewHolder, int sectionIndex, int itemIndex, int itemType) {
Section s = sections.get(sectionIndex);
ItemViewHolder ivh = (ItemViewHolder) viewHolder;
ivh.textView.setText(s.items.get(itemIndex));
ivh.adapterPositionTextView.setText(Integer.toString(getAdapterPositionForSectionItem(sectionIndex, itemIndex)));

ivh.itemView.setActivated(isSectionItemSelected(sectionIndex, itemIndex));

}

@SuppressLint("SetTextI18n")
@Override
public void onBindHeaderViewHolder(SectioningAdapter.HeaderViewHolder viewHolder, int sectionIndex, int headerType) {
Section s = sections.get(sectionIndex);
HeaderViewHolder hvh = (HeaderViewHolder) viewHolder;

hvh.textView.setText(s.header);
hvh.adapterPositionTextView.setText(Integer.toString(getAdapterPositionForSectionHeader(sectionIndex)));

hvh.itemView.setActivated(isSectionSelected(sectionIndex));

}

@SuppressLint("SetTextI18n")
@Override
public void onBindFooterViewHolder(SectioningAdapter.FooterViewHolder viewHolder, int sectionIndex, int footerType) {
Section s = sections.get(sectionIndex);
FooterViewHolder fvh = (FooterViewHolder) viewHolder;
fvh.textView.setText(s.footer);
fvh.adapterPositionTextView.setText(Integer.toString(getAdapterPositionForSectionFooter(sectionIndex)));

fvh.itemView.setActivated(isSectionFooterSelected(sectionIndex));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.LayoutRes;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
Expand Down Expand Up @@ -31,14 +34,18 @@ public class DemoActivity extends AppCompatActivity {

public static final boolean SHOW_ADAPTER_POSITIONS = true;

AppBarLayout appBarLayout;
CollapsingToolbarLayout collapsingToolbarLayout;
RecyclerView recyclerView;
ProgressBar progressBar;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
setContentView(getContentViewLayout());

appBarLayout = (AppBarLayout) findViewById(R.id.appBar);
collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsingToolbarLayout);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
progressBar = (ProgressBar) findViewById(R.id.progress);

Expand All @@ -55,6 +62,11 @@ public void onClick(View v) {
}
}

@LayoutRes
protected int getContentViewLayout(){
return R.layout.activity_demo;
}

@Override
protected void onSaveInstanceState(Bundle outState) {
RecyclerView.LayoutManager lm = recyclerView.getLayoutManager();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
Expand All @@ -12,6 +13,7 @@
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.transition.TransitionManager;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
Expand Down Expand Up @@ -151,7 +153,11 @@ void setupDemoRecyclerView() {

new DemoModel(getString(R.string.demo_list_item_paged_scroll_title),
getString(R.string.demo_list_item_paged_scroll_description),
PagedScrollDemoActivity.class)
PagedScrollDemoActivity.class),

new DemoModel(getString(R.string.demo_list_item_selection_title),
getString(R.string.demo_list_item_selection_description),
SelectionDemo.class)
};

recyclerView.setAdapter(new DemoAdapter(getContext(), demos, new ItemClickListener() {
Expand All @@ -160,7 +166,21 @@ public void onItemClick(DemoModel demoModel) {
startActivity(new Intent(getActivity(), demoModel.activityClass));
}
}));
recyclerView.setLayoutManager(new StickyHeaderLayoutManager());

StickyHeaderLayoutManager layoutManager = new StickyHeaderLayoutManager();

// set a header position callback to set elevation on sticky headers, because why not
layoutManager.setHeaderPositionChangedCallback(new StickyHeaderLayoutManager.HeaderPositionChangedCallback() {
@Override
public void onHeaderPositionChanged(int sectionIndex, View header, StickyHeaderLayoutManager.HeaderPosition oldPosition, StickyHeaderLayoutManager.HeaderPosition newPosition) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
boolean elevated = newPosition == StickyHeaderLayoutManager.HeaderPosition.STICKY;
header.setElevation(elevated ? 8 : 0);
}
}
});

recyclerView.setLayoutManager(layoutManager);
}

private static class DemoModel {
Expand Down
Loading

0 comments on commit 95cc246

Please sign in to comment.