diff options
7 files changed, 512 insertions, 115 deletions
diff --git a/samples/Support7Demos/AndroidManifest.xml b/samples/Support7Demos/AndroidManifest.xml index 4ce63b7e0..0e9ed0b93 100644 --- a/samples/Support7Demos/AndroidManifest.xml +++ b/samples/Support7Demos/AndroidManifest.xml @@ -38,6 +38,7 @@ android:compatibleWidthLimitDp="480" /> <application android:label="@string/activity_sample_code" + android:supportsRtl="true" android:icon="@drawable/app_sample_code" android:hardwareAccelerated="true"> @@ -182,5 +183,14 @@ </intent-filter> </activity> + <activity android:name=".widget.LinearLayoutManagerActivity" + android:label="@string/linear_layout_manager" + android:theme="@style/Theme.AppCompat"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.example.android.supportv7.SAMPLE_CODE" /> + </intent-filter> + </activity> + </application> </manifest> diff --git a/samples/Support7Demos/res/layout/activity_linear_layout_manager.xml b/samples/Support7Demos/res/layout/activity_linear_layout_manager.xml new file mode 100644 index 000000000..f4afe95fa --- /dev/null +++ b/samples/Support7Demos/res/layout/activity_linear_layout_manager.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <Spinner + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/spinner"/> + <android.support.v7.widget.RecyclerView + android:layout_width="fill_parent" + android:layout_height="100dp" + android:id="@+id/config_recycler_view"/> + <android.support.v7.widget.RecyclerView + android:scrollbarStyle="insideOverlay" + android:scrollbars="horizontal|vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:id="@+id/recycler_view"/> +</LinearLayout>
\ No newline at end of file diff --git a/samples/Support7Demos/res/values/strings.xml b/samples/Support7Demos/res/values/strings.xml index c36809b0d..5852d0a71 100644 --- a/samples/Support7Demos/res/values/strings.xml +++ b/samples/Support7Demos/res/values/strings.xml @@ -96,4 +96,9 @@ <string name="sample_media_route_activity_presentation">Local Playback on Presentation Display</string> <string name="recycler_view">RecyclerView</string> + <string name="linear_layout_manager">Linear Layout Manager</string> + <string name="checkbox_orientation">Horz.</string> + <string name="checkbox_reverse">Rev.</string> + <string name="checkbox_layout_dir">Layout Dir</string> + <string name="checkbox_stack_from_end">Stack From End</string> </resources> diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java new file mode 100644 index 000000000..eb49cff45 --- /dev/null +++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.supportv7.widget; + +import com.example.android.supportv7.Cheeses; +import com.example.android.supportv7.widget.adapter.SimpleStringAdapter; +import com.example.android.supportv7.widget.decorator.DividerItemDecoration; + +import android.app.Activity; +import android.os.Bundle; +import android.support.v4.view.ViewCompat; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.DisplayMetrics; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.BaseAdapter; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.LinearLayout; +import android.widget.Spinner; +import android.widget.TextView; + +import com.example.android.supportv7.R; + +/** + * A sample activity that uses {@link android.support.v7.widget.LinearLayoutManager}. + */ +public class LinearLayoutManagerActivity extends Activity { + + private LinearLayoutManager mListLayoutManager; + + private RecyclerView mRecyclerView; + + private DividerItemDecoration mDividerItemDecoration; + + private ConfigToggle[] mConfigToggles; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_linear_layout_manager); + initConfig(); + initRecyclerView(); + initSpinner(); + } + + private void initRecyclerView() { + mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view); + mRecyclerView.setHasFixedSize(true); + mListLayoutManager = new LinearLayoutManager(this); + mRecyclerView.setLayoutManager(mListLayoutManager); + mRecyclerView.setAdapter(new SimpleStringAdapter(this, Cheeses.sCheeseStrings)); + mDividerItemDecoration = new DividerItemDecoration(this, + mListLayoutManager.getOrientation()); + mRecyclerView.addItemDecoration(mDividerItemDecoration); + } + + private void initConfig() { + RecyclerView configView = (RecyclerView) findViewById(R.id.config_recycler_view); + initToggles(); + configView.setAdapter(mConfigAdapter); + configView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, + false)); + configView.setHasFixedSize(true); + } + + private void initSpinner() { + Spinner spinner = (Spinner) findViewById(R.id.spinner); + spinner.setAdapter(new BaseAdapter() { + @Override + public int getCount() { + return mRecyclerView.getAdapter().getItemCount(); + } + + @Override + public Integer getItem(int position) { + return position; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if(convertView == null) { + convertView = new TextView(parent.getContext()); + } + ((TextView) convertView).setText("" + position); + return convertView; + } + }); + spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + mRecyclerView.scrollToPosition(position); + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + + } + }); + } + + private void initToggles() { + mConfigToggles = new ConfigToggle[]{ + new ConfigToggle(R.string.checkbox_orientation) { + @Override + public boolean isChecked() { + return mListLayoutManager.getOrientation() == LinearLayoutManager.HORIZONTAL; + } + + @Override + public void onChange(boolean newValue) { + mListLayoutManager.setOrientation(newValue ? LinearLayoutManager.HORIZONTAL + : LinearLayoutManager.VERTICAL); + mDividerItemDecoration.setOrientation(mListLayoutManager.getOrientation()); + } + }, + new ConfigToggle(R.string.checkbox_reverse) { + @Override + public boolean isChecked() { + return mListLayoutManager.getReverseLayout(); + } + + @Override + public void onChange(boolean newValue) { + mListLayoutManager.setReverseLayout(newValue); + } + }, + new ConfigToggle(R.string.checkbox_layout_dir) { + @Override + public boolean isChecked() { + return ViewCompat.getLayoutDirection(mRecyclerView) == + ViewCompat.LAYOUT_DIRECTION_RTL; + } + + @Override + public void onChange(boolean newValue) { + ViewCompat.setLayoutDirection(mRecyclerView, newValue ? + ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR); + } + }, + new ConfigToggle(R.string.checkbox_stack_from_end) { + @Override + public boolean isChecked() { + return mListLayoutManager.getStackFromEnd(); + } + + @Override + public void onChange(boolean newValue) { + mListLayoutManager.setStackFromEnd(newValue); + } + } + }; + } + + private class ConfigViewHolder extends RecyclerView.ViewHolder + implements CompoundButton.OnCheckedChangeListener { + + private CheckBox mCheckBox; + + private ConfigToggle mConfigToggle; + + public ConfigViewHolder(View itemView) { + super(itemView); + mCheckBox = (CheckBox) itemView; + mCheckBox.setOnCheckedChangeListener(this); + } + + public void render(ConfigToggle toggle) { + mConfigToggle = toggle; + mCheckBox.setText(toggle.getText()); + mCheckBox.setChecked(toggle.isChecked()); + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (mConfigToggle != null) { + mConfigToggle.onChange(isChecked); + } + } + } + + + private abstract class ConfigToggle { + + private String mLabel; + + protected ConfigToggle(int labelId) { + mLabel = getResources().getString(labelId); + } + + public String getText() { + return mLabel; + } + + abstract public boolean isChecked(); + + abstract public void onChange(boolean newValue); + } + + + + private RecyclerView.Adapter mConfigAdapter = new RecyclerView.Adapter<ConfigViewHolder>() { + @Override + public ConfigViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new ConfigViewHolder(new CheckBox(parent.getContext())); + } + + @Override + public void onBindViewHolder(ConfigViewHolder holder, int position) { + ConfigToggle toggle = mConfigToggles[position]; + holder.render(toggle); + } + + @Override + public int getItemCount() { + return mConfigToggles.length; + } + }; + +} diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java index 5692cb87c..223da652f 100644 --- a/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java +++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java @@ -17,30 +17,23 @@ package com.example.android.supportv7.widget; -import android.R; +import com.example.android.supportv7.Cheeses; +import com.example.android.supportv7.widget.adapter.SimpleStringAdapter; +import com.example.android.supportv7.widget.decorator.DividerItemDecoration; + import android.app.Activity; import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.v4.view.MenuItemCompat; import android.support.v7.widget.RecyclerView; import android.util.DisplayMetrics; -import android.util.Log; -import android.util.TypedValue; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; -import com.example.android.supportv7.Cheeses; - -import java.util.ArrayList; -import java.util.Collections; public class RecyclerViewActivity extends Activity { + private static final String TAG = "RecyclerViewActivity"; private RecyclerView mRecyclerView; @@ -54,12 +47,26 @@ public class RecyclerViewActivity extends Activity { rv.setHasFixedSize(true); rv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - rv.setAdapter(new MyAdapter(Cheeses.sCheeseStrings)); - - rv.addItemDecoration(new DividerItemDecoration(this)); - + rv.setAdapter(new SimpleStringAdapter(this, Cheeses.sCheeseStrings) { + @Override + public SimpleStringAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, + int viewType) { + final SimpleStringAdapter.ViewHolder vh = super + .onCreateViewHolder(parent, viewType); + vh.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + final int pos = vh.getPosition(); + if (pos + 1 < getItemCount()) { + swap(pos, pos + 1); + } + } + }); + return vh; + } + }); + rv.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)); setContentView(rv); - mRecyclerView = rv; } @@ -82,8 +89,11 @@ public class RecyclerViewActivity extends Activity { * A basic ListView-style LayoutManager. */ class MyLayoutManager extends RecyclerView.LayoutManager { + private static final String TAG = "MyLayoutManager"; + private int mFirstPosition; + private final int mScrollDistance; public MyLayoutManager(Context c) { @@ -268,102 +278,4 @@ public class RecyclerViewActivity extends Activity { } } } - - class MyAdapter extends RecyclerView.Adapter<ViewHolder> { - private int mBackground; - private ArrayList<String> mValues; - - public MyAdapter(String[] strings) { - TypedValue val = new TypedValue(); - RecyclerViewActivity.this.getTheme().resolveAttribute( - R.attr.selectableItemBackground, val, true); - mBackground = val.resourceId; - mValues = new ArrayList<String>(); - Collections.addAll(mValues, strings); - } - - @Override - public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - final ViewHolder h = new ViewHolder(new TextView(RecyclerViewActivity.this)); - h.textView.setMinimumHeight(128); - h.textView.setFocusable(true); - h.textView.setBackgroundResource(mBackground); - h.textView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - final int pos = h.getPosition(); - if (mValues.size() > pos + 1) { - final String t = mValues.get(pos); - mValues.set(pos, mValues.get(pos + 1)); - mValues.set(pos + 1, t); - notifyItemRemoved(pos); - notifyItemInserted(pos + 1); - } - } - }); - return h; - } - - @Override - public void onBindViewHolder(ViewHolder holder, int position) { - holder.textView.setText(mValues.get(position)); - } - - @Override - public int getItemCount() { - return mValues.size(); - } - } - - static class ViewHolder extends RecyclerView.ViewHolder { - public TextView textView; - - public ViewHolder(TextView v) { - super(v); - textView = v; - } - - @Override - public String toString() { - return super.toString() + " '" + textView.getText(); - } - } - - static class DividerItemDecoration extends RecyclerView.ItemDecoration { - private static final int[] ATTRS = new int[] { - R.attr.listDivider - }; - - private Drawable mDivider; - - public DividerItemDecoration(Context context) { - final TypedArray a = context.obtainStyledAttributes(ATTRS); - mDivider = a.getDrawable(0); - a.recycle(); - } - - public DividerItemDecoration(Drawable divider) { - mDivider = divider; - } - - @Override - public void onDraw(Canvas c, RecyclerView parent) { - final int left = parent.getPaddingLeft(); - final int right = parent.getWidth() - parent.getPaddingRight(); - - final int childCount = parent.getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = parent.getChildAt(i); - final int top = child.getBottom(); - final int bottom = top + mDivider.getIntrinsicHeight(); - mDivider.setBounds(left, top, right, bottom); - mDivider.draw(c); - } - } - - @Override - public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { - outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); - } - } } diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/adapter/SimpleStringAdapter.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/adapter/SimpleStringAdapter.java new file mode 100644 index 000000000..110eb626a --- /dev/null +++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/adapter/SimpleStringAdapter.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.supportv7.widget.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.Collections; + +public class SimpleStringAdapter extends RecyclerView.Adapter<SimpleStringAdapter.ViewHolder> { + + private int mBackground; + + private ArrayList<String> mValues; + + public static class ViewHolder extends RecyclerView.ViewHolder { + + public TextView textView; + + public ViewHolder(TextView v) { + super(v); + textView = v; + } + + @Override + public String toString() { + return super.toString() + " '" + textView.getText(); + } + } + + public SimpleStringAdapter(Context context, String[] strings) { + TypedValue val = new TypedValue(); + if (context.getTheme() != null) { + context.getTheme().resolveAttribute( + android.R.attr.selectableItemBackground, val, true); + } + mBackground = val.resourceId; + mValues = new ArrayList<String>(); + Collections.addAll(mValues, strings); + } + + public void swap(int pos1, int pos2) { + String tmp = mValues.get(pos1); + mValues.set(pos1, mValues.get(pos2)); + mValues.set(pos2, tmp); + notifyItemRemoved(pos1); + notifyItemInserted(pos2); + } + + @Override + public SimpleStringAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + final ViewHolder h = new ViewHolder(new TextView(parent.getContext())); + h.textView.setMinimumHeight(128); + h.textView.setPadding(20, 0, 20, 0); + h.textView.setFocusable(true); + h.textView.setBackgroundResource(mBackground); + return h; + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + holder.textView.setText(position + ":" + mValues.get(position)); + } + + @Override + public int getItemCount() { + return mValues.size(); + } +} diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/decorator/DividerItemDecoration.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/decorator/DividerItemDecoration.java new file mode 100644 index 000000000..4d5d2083a --- /dev/null +++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/decorator/DividerItemDecoration.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.supportv7.widget.decorator; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +public class DividerItemDecoration extends RecyclerView.ItemDecoration { + + private static final int[] ATTRS = new int[]{ + android.R.attr.listDivider + }; + + public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; + + public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; + + private Drawable mDivider; + + private int mOrientation; + + public DividerItemDecoration(Context context, int orientation) { + final TypedArray a = context.obtainStyledAttributes(ATTRS); + mDivider = a.getDrawable(0); + a.recycle(); + setOrientation(orientation); + } + + public void setOrientation(int orientation) { + if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { + throw new IllegalArgumentException("invalid orientation"); + } + mOrientation = orientation; + } + + @Override + public void onDraw(Canvas c, RecyclerView parent) { + if (mOrientation == VERTICAL_LIST) { + drawVertical(c, parent); + } else { + drawHorizontal(c, parent); + } + } + + public void drawVertical(Canvas c, RecyclerView parent) { + final int left = parent.getPaddingLeft(); + final int right = parent.getWidth() - parent.getPaddingRight(); + + final int childCount = parent.getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = parent.getChildAt(i); + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child + .getLayoutParams(); + final int top = child.getBottom() + params.bottomMargin; + final int bottom = top + mDivider.getIntrinsicHeight(); + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(c); + } + } + + public void drawHorizontal(Canvas c, RecyclerView parent) { + final int top = parent.getPaddingTop(); + final int bottom = parent.getHeight() - parent.getPaddingBottom(); + + final int childCount = parent.getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = parent.getChildAt(i); + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child + .getLayoutParams(); + final int left = child.getRight() + params.rightMargin; + final int right = left + mDivider.getIntrinsicHeight(); + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(c); + } + } + + @Override + public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { + if (mOrientation == VERTICAL_LIST) { + outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); + } else { + outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); + } + } +} |