add flutter
@@ -0,0 +1,9 @@
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
/.idea
|
||||
*iml
|
||||
@@ -0,0 +1,23 @@
|
||||
Copyright (c) 2015, DoAT Media Ltd.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,266 @@
|
||||
> **Announcement**
|
||||
>
|
||||
> An update regarding Bintray's shutdown: The library has been successfuly republished onto maven central, but with a different Group ID; Please update your Gradle dependencies as follows:
|
||||
>
|
||||
> ```diff
|
||||
> -implementation 'me.everything:overscroll-decor-android:1.1.0'
|
||||
> +implementation 'io.github.everythingme:overscroll-decor-android:1.1.1'
|
||||
> ```
|
||||
|
||||
# Over-Scroll Support For Android's RecyclerView, ListView, GridView, ScrollView ...
|
||||
|
||||
The library provides an iOS-like over-scrolling effect applicable over almost all Android native scrollable views. It is also built to allow for very easy adaptation to support custom views.
|
||||
|
||||
The core effect classes are loose-[decorators](https://en.wikipedia.org/wiki/Decorator_pattern) of Android views, and are thus decoupled from the actual view classes' implementations. That allows developers to apply the effect over views while keeping them as untampered 'black-boxes'. Namely, it allows for keeping important optimizations such as view-recycling intact.
|
||||
|
||||

|
||||
|
||||
# Gradle Dependency
|
||||
|
||||
Add the following to your module's `build.gradle` file:
|
||||
|
||||
```groovy
|
||||
dependencies {
|
||||
// ...
|
||||
|
||||
implementation 'io.github.everythingme:overscroll-decor-android:1.1.1'
|
||||
}
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
||||
### RecyclerView
|
||||
|
||||
Supports both linear and staggered-grid layout managers (i.e. all native Android layouts).
|
||||
Can be easily adapted to support custom layout managers.
|
||||
|
||||
```java
|
||||
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
|
||||
|
||||
// Horizontal
|
||||
OverScrollDecoratorHelper.setUpOverScroll(recyclerView, OverScrollDecoratorHelper.ORIENTATION_HORIZONTAL);
|
||||
// Vertical
|
||||
OverScrollDecoratorHelper.setUpOverScroll(recyclerView, OverScrollDecoratorHelper.ORIENTATION_VERTICAL);
|
||||
```
|
||||
|
||||
### RecyclerView with items swiping / dragging
|
||||
See _Advanced Usage_.
|
||||
|
||||
|
||||
### ListView
|
||||
|
||||
```java
|
||||
ListView listView = (ListView) findViewById(R.id.list_view);
|
||||
OverScrollDecoratorHelper.setUpOverScroll(listView);
|
||||
```
|
||||
|
||||
### GridView
|
||||
|
||||
```java
|
||||
GridView gridView = (GridView) findViewById(R.id.grid_view);
|
||||
OverScrollDecoratorHelper.setUpOverScroll(gridView);
|
||||
```
|
||||
|
||||
### ViewPager
|
||||
|
||||
```java
|
||||
ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
|
||||
OverScrollDecoratorHelper.setUpOverScroll(viewPager);
|
||||
```
|
||||
|
||||
### ScrollView, HorizontalScrollView
|
||||
|
||||
```java
|
||||
ScrollView scrollView = (ScrollView) findViewById(R.id.scroll_view);
|
||||
OverScrollDecoratorHelper.setUpOverScroll(scrollView);
|
||||
|
||||
HorizontalScrollView horizontalScrollView = (HorizontalScrollView) findViewById(R.id.horizontal_scroll_view);
|
||||
OverScrollDecoratorHelper.setUpOverScroll(horizontalScrollView);
|
||||
```
|
||||
|
||||
### Any View - Text, Image... (Always Over-Scroll Ready)
|
||||
|
||||
```java
|
||||
View view = findViewById(R.id.demo_view);
|
||||
|
||||
// Horizontal
|
||||
OverScrollDecoratorHelper.setUpStaticOverScroll(view, OverScrollDecoratorHelper.ORIENTATION_HORIZONTAL);
|
||||
// Vertical
|
||||
OverScrollDecoratorHelper.setUpStaticOverScroll(view, OverScrollDecoratorHelper.ORIENTATION_VERTICAL);
|
||||
```
|
||||
|
||||
# Advanced Usage
|
||||
|
||||
```java
|
||||
// Horizontal RecyclerView
|
||||
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
|
||||
new HorizontalOverScrollBounceEffectDecorator(new RecyclerViewOverScrollDecorAdapter(recyclerView));
|
||||
|
||||
// ListView (vertical)
|
||||
ListView listView = (ListView) findViewById(R.id.list_view);
|
||||
new VerticalOverScrollBounceEffectDecorator(new AbsListViewOverScrollDecorAdapter(listView));
|
||||
|
||||
// GridView (vertical)
|
||||
GridView gridView = (GridView) findViewById(R.id.grid_view);
|
||||
new VerticalOverScrollBounceEffectDecorator(new AbsListViewOverScrollDecorAdapter(gridView));
|
||||
|
||||
// ViewPager
|
||||
ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
|
||||
new HorizontalOverScrollBounceEffectDecorator(new ViewPagerOverScrollDecorAdapter(viewPager));
|
||||
|
||||
// A simple TextView - horizontal
|
||||
View textView = findViewById(R.id.title);
|
||||
new HorizontalOverScrollBounceEffectDecorator(new StaticOverScrollDecorAdapter(view));
|
||||
```
|
||||
|
||||
### RecyclerView with [ItemTouchHelper](http://developer.android.com/reference/android/support/v7/widget/helper/ItemTouchHelper.html) based swiping / dragging
|
||||
As of version 1.0.1, the effect can work smoothly with the RecyclerView's built-in mechanism for items swiping and dragging (based on [ItemTouchHelper](http://developer.android.com/reference/android/support/v7/widget/helper/ItemTouchHelper.html)). BUT, it requires some (very little) explicit configuration work:
|
||||
|
||||
```java
|
||||
// Normally you would attach an ItemTouchHelper & a callback to a RecyclerView, this way:
|
||||
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
|
||||
ItemTouchHelper.Callback myCallback = new ItemTouchHelper.Callback() {
|
||||
...
|
||||
};
|
||||
ItemTouchHelper myHelper = new ItemTouchHelper(myCallback);
|
||||
myHelper.attachToRecyclerView(recyclerView);
|
||||
|
||||
// INSTEAD of attaching the helper yourself, simply use the dedicated adapter c'tor, e.g.:
|
||||
new VerticalOverScrollBounceEffectDecorator(new RecyclerViewOverScrollDecorAdapter(recyclerView, myCallback));
|
||||
|
||||
```
|
||||
|
||||
For more info on the swiping / dragging mechanism, try [this useful tutorial](https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-b9456d2b1aaf).
|
||||
|
||||
### Over-Scroll Listeners
|
||||
As of version 1.0.2, the effect provides a means for registering listeners of over-scroll related events. There are two types of listeners, as follows.
|
||||
|
||||
#### State-Change Listener
|
||||
The over-scroll manager dispatches events onto a state-change listener denoting transitions in the effect's state:
|
||||
|
||||
```java
|
||||
|
||||
// Note: over-scroll is set-up using the helper method.
|
||||
IOverScrollDecor decor = OverScrollDecoratorHelper.setUpOverScroll(recyclerView, OverScrollDecoratorHelper.ORIENTATION_HORIZONTAL);
|
||||
|
||||
decor.setOverScrollStateListener(new IOverScrollStateListener() {
|
||||
@Override
|
||||
public void onOverScrollStateChange(IOverScrollDecor decor, int oldState, int newState) {
|
||||
switch (newState) {
|
||||
case STATE_IDLE:
|
||||
// No over-scroll is in effect.
|
||||
break;
|
||||
case STATE_DRAG_START_SIDE:
|
||||
// Dragging started at the left-end.
|
||||
break;
|
||||
case STATE_DRAG_END_SIDE:
|
||||
// Dragging started at the right-end.
|
||||
break;
|
||||
case STATE_BOUNCE_BACK:
|
||||
if (oldState == STATE_DRAG_START_SIDE) {
|
||||
// Dragging stopped -- view is starting to bounce back from the *left-end* onto natural position.
|
||||
} else { // i.e. (oldState == STATE_DRAG_END_SIDE)
|
||||
// View is starting to bounce back from the *right-end*.
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Real-time Updates Listener
|
||||
The over-scroll manager can also dispatch *real-time*, as-it-happens over-scroll events denoting the current offset resulting due to an over-scroll being in-effect (the offset thus denotes the current 'intensity').
|
||||
|
||||
```java
|
||||
// Note: over-scroll is set-up by explicity instantiating a decorator rather than using the helper; The two methods can be used interchangeably for registering listeners.
|
||||
VerticalOverScrollBounceEffectDecorator decor = new VerticalOverScrollBounceEffectDecorator(new RecyclerViewOverScrollDecorAdapter(recyclerView, itemTouchHelperCallback));
|
||||
|
||||
decor.setOverScrollUpdateListener(new IOverScrollUpdateListener() {
|
||||
@Override
|
||||
public void onOverScrollUpdate(IOverScrollDecor decor, int state, float offset) {
|
||||
final View view = decor.getView();
|
||||
if (offset > 0) {
|
||||
// 'view' is currently being over-scrolled from the top.
|
||||
} else if (offset < 0) {
|
||||
// 'view' is currently being over-scrolled from the bottom.
|
||||
} else {
|
||||
// No over-scroll is in-effect.
|
||||
// This is synonymous with having (state == STATE_IDLE).
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
|
||||
The two type of listeners can be used either separately or in conjunction, depending on your needs. Refer to the demo project's RecyclerView-demo section for actual concrete usage.
|
||||
|
||||
### Custom Views
|
||||
|
||||
```java
|
||||
public class CustomView extends View {
|
||||
// ...
|
||||
}
|
||||
|
||||
final CustomView view = (CustomView) findViewById(R.id.custom_view);
|
||||
new VerticalOverScrollBounceEffectDecorator(new IOverScrollDecoratorAdapter() {
|
||||
|
||||
@Override
|
||||
public View getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInAbsoluteStart() {
|
||||
// canScrollUp() is an example of a method you must implement
|
||||
return !view.canScrollUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInAbsoluteEnd() {
|
||||
// canScrollDown() is an example of a method you must implement
|
||||
return !view.canScrollDown();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Effect Behavior Configuration
|
||||
|
||||
```java
|
||||
/// Make over-scroll applied over a list-view feel more 'stiff'
|
||||
new VerticalOverScrollBounceEffectDecorator(new AbsListViewOverScrollDecorAdapter(view),
|
||||
5f, // Default is 3
|
||||
VerticalOverScrollBounceEffectDecorator.DEFAULT_TOUCH_DRAG_MOVE_RATIO_BCK,
|
||||
VerticalOverScrollBounceEffectDecorator.DEFAULT_DECELERATE_FACTOR);
|
||||
|
||||
// Make over-scroll applied over a list-view bounce-back more softly
|
||||
new VerticalOverScrollBounceEffectDecorator(new AbsListViewOverScrollDecorAdapter(view),
|
||||
VerticalOverScrollBounceEffectDecorator.DEFAULT_TOUCH_DRAG_MOVE_RATIO_FWD,
|
||||
VerticalOverScrollBounceEffectDecorator.DEFAULT_TOUCH_DRAG_MOVE_RATIO_BCK,
|
||||
-1f // Default is -2
|
||||
);
|
||||
```
|
||||
|
||||
### Dynamic Effect Disabling
|
||||
|
||||
As of version 1.0.4, the effect can be dynamically disabled (detached) and reenabled (attached) at runtime:
|
||||
|
||||
```java
|
||||
IOverScrollDecor decor = OverScrollDecoratorHelper.setUpOverScroll(view);
|
||||
|
||||
// Detach. You are strongly encouraged to only call this when overscroll isn't
|
||||
// in-effect: Either add getCurrentState()==STATE_IDLE as a precondition,
|
||||
// or use a state-change listener.
|
||||
decor.detach();
|
||||
// Attach.
|
||||
decor.attach();
|
||||
```
|
||||
|
||||
`attach()` and `detach()` can be used repeatedly - as necessary, as can be seen in the demo project (refer to action-bar menu in recycler-view demo).
|
||||
|
||||
## Credits
|
||||
|
||||
App icons by <a href="http://somerandomdude.com/work/iconic/">P.J. Onori</a>,
|
||||
<a href="http://graphicriver.net/item/wirecons-vector-icons/4586710?ref=tmthymllr">Timothy Miller</a>,
|
||||
<a href="http://icons4android.com">Icons4Android</a>,
|
||||
<a href="http://icons8.com/android-icons">Icons8.com</a>
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,27 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion '29.0.3'
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'me.everything.overscrolldemo'
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName '1.0'
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'com.google.android.material:material:1.3.0'
|
||||
implementation project(':liboverscroll')
|
||||
// implementation 'io.github.everythingme:overscroll-decor-android:1.1.1'
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /Users/amit/Library/Android/sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="me.everything.overscrolldemo" >
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/app_icon"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity
|
||||
android:name=".OverScrollDemoActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme.NoActionBar" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,105 @@
|
||||
package me.everything.overscrolldemo;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import com.google.android.material.navigation.NavigationView;
|
||||
import androidx.core.view.GravityCompat;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import me.everything.overscrolldemo.view.GridViewDemoFragment;
|
||||
import me.everything.overscrolldemo.view.ListViewDemoFragment;
|
||||
import me.everything.overscrolldemo.view.MiscViewsDemoFragment;
|
||||
import me.everything.overscrolldemo.view.NestedScrollViewDemoFragment;
|
||||
import me.everything.overscrolldemo.view.RecyclerViewDemoFragment;
|
||||
import me.everything.overscrolldemo.view.RecyclerViewStaggeredGridDemoFragment;
|
||||
import me.everything.overscrolldemo.view.ScrollViewDemoFragment;
|
||||
import me.everything.overscrolldemo.view.ViewPagerDemoFragment;
|
||||
|
||||
public class OverScrollDemoActivity extends AppCompatActivity
|
||||
implements NavigationView.OnNavigationItemSelectedListener {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_overscroll_demo);
|
||||
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
toolbar.setTitle(R.string.recycler_view_demo_title);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
|
||||
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
|
||||
drawer.addDrawerListener(toggle);
|
||||
toggle.syncState();
|
||||
|
||||
NavigationView navigationView = (NavigationView) findViewById(R.id.drawer_nav);
|
||||
navigationView.setNavigationItemSelectedListener(this);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.add(R.id.fragment_placeholder, new RecyclerViewDemoFragment())
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||
if (drawer.isDrawerOpen(GravityCompat.START)) {
|
||||
drawer.closeDrawer(GravityCompat.START);
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(MenuItem item) {
|
||||
final int id = item.getItemId();
|
||||
item.setChecked(true);
|
||||
|
||||
switch (id) {
|
||||
case R.id.drawer_item_recyclerview_demo:
|
||||
replaceMainFragment(new RecyclerViewDemoFragment(), R.string.recycler_view_demo_title);
|
||||
break;
|
||||
case R.id.drawer_item_gridview_demo:
|
||||
replaceMainFragment(new GridViewDemoFragment(), R.string.grid_view_demo_title);
|
||||
break;
|
||||
case R.id.drawer_item_listview_demo:
|
||||
replaceMainFragment(new ListViewDemoFragment(), R.string.list_view_demo_title);
|
||||
break;
|
||||
case R.id.drawer_item_recyclerview_staggered_grid_demo:
|
||||
replaceMainFragment(new RecyclerViewStaggeredGridDemoFragment(), R.string.recycler_view_staggered_grid_demo_title);
|
||||
break;
|
||||
case R.id.drawer_item_scrollview_demo:
|
||||
replaceMainFragment(new ScrollViewDemoFragment(), R.string.scroll_view_demo_title);
|
||||
break;
|
||||
case R.id.drawer_item_viewpager_demo:
|
||||
replaceMainFragment(new ViewPagerDemoFragment(),R.string.viewpager_demo_title);
|
||||
break;
|
||||
case R.id.drawer_item_nested_scrollview_demo:
|
||||
replaceMainFragment(new NestedScrollViewDemoFragment(), R.string.nested_scrollview_demo_title);
|
||||
break;
|
||||
case R.id.drawer_item_misc_demo:
|
||||
replaceMainFragment(new MiscViewsDemoFragment(), R.string.misc_views_demo_title);
|
||||
break;
|
||||
}
|
||||
|
||||
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||
drawer.closeDrawer(GravityCompat.START);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void replaceMainFragment(Fragment fragment, int titleResId) {
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.setCustomAnimations(R.animator.fade_in_slow, R.animator.fade_out_quick)
|
||||
.replace(R.id.fragment_placeholder, fragment)
|
||||
.commit();
|
||||
getSupportActionBar().setTitle(titleResId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package me.everything.overscrolldemo.control;
|
||||
|
||||
import android.content.res.Resources;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import me.everything.overscrolldemo.R;
|
||||
|
||||
public class DemoContentHelper {
|
||||
|
||||
private static List<DemoItem> sSpectrumItemsVioletToRed;
|
||||
private static List<DemoItem> sSpectrumItemsRedToViolet;
|
||||
|
||||
public static List<DemoItem> getSpectrumItems(Resources res) {
|
||||
if (sSpectrumItemsVioletToRed == null) {
|
||||
sSpectrumItemsVioletToRed = Arrays.asList(
|
||||
new DemoItem(res.getColor(android.R.color.holo_purple), "PURPLE"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_blue_dark), "BLUE"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_blue_light), "LIGHT BLUE"),
|
||||
new DemoItem(res.getColor(R.color.spectrum_cyan), "CYAN"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_green_dark), "GREEN"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_green_light), "LIGHT GREEN"),
|
||||
new DemoItem(res.getColor(R.color.spectrum_yellow), "YELLOW"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_orange_light), "LIGHT ORANGE"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_orange_dark), "ORANGE"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_red_light), "LIGHT RED"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_red_dark), "RED")
|
||||
);
|
||||
}
|
||||
return sSpectrumItemsVioletToRed;
|
||||
}
|
||||
|
||||
public static List<DemoItem> getReverseSpectrumItems(Resources res) {
|
||||
if (sSpectrumItemsRedToViolet == null) {
|
||||
sSpectrumItemsRedToViolet = Arrays.asList(
|
||||
new DemoItem(res.getColor(android.R.color.holo_red_dark), "RED"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_red_light), "LIGHT RED"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_orange_dark), "ORANGE"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_orange_light), "LIGHT ORANGE"),
|
||||
new DemoItem(res.getColor(R.color.spectrum_yellow), "YELLOW"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_green_light), "LIGHT GREEN"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_green_dark), "GREEN"),
|
||||
new DemoItem(res.getColor(R.color.spectrum_cyan), "CYAN"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_blue_light), "LIGHT BLUE"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_blue_dark), "BLUE"),
|
||||
new DemoItem(res.getColor(android.R.color.holo_purple), "PURPLE")
|
||||
);
|
||||
}
|
||||
return sSpectrumItemsRedToViolet;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package me.everything.overscrolldemo.control;
|
||||
|
||||
public class DemoItem {
|
||||
|
||||
private int mColor;
|
||||
private String mColorName;
|
||||
|
||||
public DemoItem() {
|
||||
}
|
||||
|
||||
public DemoItem(int color, String colorName) {
|
||||
mColorName = colorName;
|
||||
mColor = color;
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return mColor;
|
||||
}
|
||||
|
||||
public void setColor(int color) {
|
||||
mColor = color;
|
||||
}
|
||||
|
||||
public String getColorName() {
|
||||
return mColorName;
|
||||
}
|
||||
|
||||
public void setColorName(String colorName) {
|
||||
mColorName = colorName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package me.everything.overscrolldemo.view;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.everything.overscrolldemo.R;
|
||||
import me.everything.overscrolldemo.control.DemoItem;
|
||||
|
||||
public class DemoGridAdapter extends DemoListAdapterBase {
|
||||
|
||||
protected DemoGridAdapter(LayoutInflater inflater) {
|
||||
super(inflater);
|
||||
}
|
||||
|
||||
public DemoGridAdapter(LayoutInflater inflater, List<DemoItem> items) {
|
||||
super(inflater, items);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DemoViewHolder createViewHolder(ViewGroup parent) {
|
||||
return new DemoViewHolder(R.layout.grid_item, parent, mInflater);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package me.everything.overscrolldemo.view;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.everything.overscrolldemo.R;
|
||||
import me.everything.overscrolldemo.control.DemoItem;
|
||||
|
||||
public class DemoListAdapter extends DemoListAdapterBase {
|
||||
|
||||
protected DemoListAdapter(LayoutInflater inflater) {
|
||||
super(inflater);
|
||||
}
|
||||
|
||||
public DemoListAdapter(LayoutInflater inflater, List<DemoItem> items) {
|
||||
super(inflater, items);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DemoViewHolder createViewHolder(ViewGroup parent) {
|
||||
return new DemoViewHolder(R.layout.vertical_list_item, parent, mInflater);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package me.everything.overscrolldemo.view;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.everything.overscrolldemo.control.DemoItem;
|
||||
|
||||
public abstract class DemoListAdapterBase extends BaseAdapter {
|
||||
|
||||
private static final int COLOR_VIEW_TYPE = 0;
|
||||
|
||||
public static class DemoViewHolder {
|
||||
|
||||
TextView mTextView;
|
||||
|
||||
public DemoViewHolder(int resId, ViewGroup parent, LayoutInflater inflater) {
|
||||
mTextView = (TextView) inflater.inflate(resId, parent, false);
|
||||
mTextView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Toast.makeText(mTextView.getContext(), "Tapped on: "+mTextView.getText(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
mTextView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
Toast.makeText(mTextView.getContext(), "Long-tapped on: "+mTextView.getText(), Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void init(DemoItem item) {
|
||||
mTextView.setText(item.getColorName());
|
||||
|
||||
int color = item.getColor();
|
||||
mTextView.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
return mTextView;
|
||||
}
|
||||
}
|
||||
|
||||
protected final LayoutInflater mInflater;
|
||||
protected List<DemoItem> mItems;
|
||||
|
||||
protected DemoListAdapterBase(LayoutInflater inflater) {
|
||||
mInflater = inflater;
|
||||
}
|
||||
|
||||
public DemoListAdapterBase(LayoutInflater inflater, List<DemoItem> items) {
|
||||
mInflater = inflater;
|
||||
mItems = items;
|
||||
}
|
||||
|
||||
public void setItems(List items) {
|
||||
mItems = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return mItems.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
|
||||
DemoViewHolder holder;
|
||||
if (convertView == null) {
|
||||
holder = createViewHolder(parent);
|
||||
holder.getView().setTag(holder);
|
||||
} else {
|
||||
holder = (DemoViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
holder.init((DemoItem) getItem(position));
|
||||
return holder.getView();
|
||||
}
|
||||
|
||||
protected abstract DemoViewHolder createViewHolder(ViewGroup parent);
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return COLOR_VIEW_TYPE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package me.everything.overscrolldemo.view;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.everything.overscrolldemo.control.DemoItem;
|
||||
|
||||
public abstract class DemoRecyclerAdapterBase extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
private static final int COLOR_VIEW_TYPE = 0;
|
||||
|
||||
public static class DemoViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public DemoViewHolder(int resId, ViewGroup parent, LayoutInflater inflater) {
|
||||
super(inflater.inflate(resId, parent, false));
|
||||
|
||||
getTextView().setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Toast.makeText(getTextView().getContext(), "Tapped on: "+getTextView().getText(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
getTextView().setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
Toast.makeText(getTextView().getContext(), "Long-tapped on: "+getTextView().getText(), Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void init(DemoItem item) {
|
||||
TextView textView = getTextView();
|
||||
textView.setText(item.getColorName());
|
||||
|
||||
int color = item.getColor();
|
||||
textView.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
private TextView getTextView() {
|
||||
return (TextView) itemView;
|
||||
}
|
||||
}
|
||||
|
||||
protected final LayoutInflater mInflater;
|
||||
protected List<DemoItem> mItems;
|
||||
|
||||
protected DemoRecyclerAdapterBase(LayoutInflater inflater) {
|
||||
mInflater = inflater;
|
||||
}
|
||||
|
||||
public DemoRecyclerAdapterBase(LayoutInflater inflater, List<DemoItem> items) {
|
||||
mInflater = inflater;
|
||||
mItems = items;
|
||||
}
|
||||
|
||||
public void setItems(List items) {
|
||||
mItems = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
||||
DemoItem item = mItems.get(position);
|
||||
|
||||
DemoViewHolder demoHolder = (DemoViewHolder) holder;
|
||||
demoHolder.init(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return COLOR_VIEW_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package me.everything.overscrolldemo.view;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.everything.overscrolldemo.R;
|
||||
|
||||
public class DemoRecyclerAdapterHorizontal extends DemoRecyclerAdapterBase {
|
||||
|
||||
public DemoRecyclerAdapterHorizontal(LayoutInflater inflater) {
|
||||
super(inflater);
|
||||
}
|
||||
|
||||
public DemoRecyclerAdapterHorizontal(List items, LayoutInflater inflater) {
|
||||
super(inflater, items);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return new DemoViewHolder(R.layout.horizontal_list_item, parent, mInflater);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package me.everything.overscrolldemo.view;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.everything.overscrolldemo.R;
|
||||
|
||||
public class DemoRecyclerAdapterVertical extends DemoRecyclerAdapterBase {
|
||||
|
||||
public DemoRecyclerAdapterVertical(LayoutInflater inflater) {
|
||||
super(inflater);
|
||||
}
|
||||
|
||||
public DemoRecyclerAdapterVertical(List items, LayoutInflater inflater) {
|
||||
super(inflater, items);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return new DemoViewHolder(R.layout.vertical_list_item, parent, mInflater);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package me.everything.overscrolldemo.view;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ListAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.everything.android.ui.overscroll.OverScrollDecoratorHelper;
|
||||
import me.everything.overscrolldemo.R;
|
||||
import me.everything.overscrolldemo.control.DemoContentHelper;
|
||||
import me.everything.overscrolldemo.control.DemoItem;
|
||||
|
||||
public class GridViewDemoFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View fragmentView = inflater.inflate(R.layout.gridview_overscroll_demo, null, false);
|
||||
initVerticalGridView(DemoContentHelper.getSpectrumItems(getResources()), (GridView) fragmentView.findViewById(R.id.grid_view));
|
||||
return fragmentView;
|
||||
}
|
||||
|
||||
private void initVerticalGridView(List<DemoItem> content, GridView gridView) {
|
||||
LayoutInflater appInflater = LayoutInflater.from(getActivity().getApplicationContext());
|
||||
ListAdapter adapter = new DemoGridAdapter(appInflater, content);
|
||||
gridView.setAdapter(adapter);
|
||||
|
||||
OverScrollDecoratorHelper.setUpOverScroll(gridView);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package me.everything.overscrolldemo.view;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.everything.android.ui.overscroll.OverScrollDecoratorHelper;
|
||||
import me.everything.overscrolldemo.R;
|
||||
import me.everything.overscrolldemo.control.DemoContentHelper;
|
||||
import me.everything.overscrolldemo.control.DemoItem;
|
||||
|
||||
public class ListViewDemoFragment extends Fragment {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View fragmentView = inflater.inflate(R.layout.listview_overscroll_demo, null, false);
|
||||
initVerticalListView(DemoContentHelper.getSpectrumItems(getResources()), (ListView) fragmentView.findViewById(R.id.list_view));
|
||||
return fragmentView;
|
||||
}
|
||||
|
||||
private void initVerticalListView(List<DemoItem> content, ListView listView) {
|
||||
LayoutInflater appInflater = LayoutInflater.from(getActivity().getApplicationContext());
|
||||
ListAdapter adapter = new DemoListAdapter(appInflater, content);
|
||||
listView.setAdapter(adapter);
|
||||
|
||||
OverScrollDecoratorHelper.setUpOverScroll(listView);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package me.everything.overscrolldemo.view;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Chronometer;
|
||||
|
||||
import me.everything.android.ui.overscroll.OverScrollDecoratorHelper;
|
||||
import me.everything.overscrolldemo.R;
|
||||
|
||||
public class MiscViewsDemoFragment extends Fragment {
|
||||
|
||||
private static final String CHRONO_TIME_SAVE_ID = "chronoTime";
|
||||
|
||||
private Chronometer mChrono;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View fragmentView = inflater.inflate(R.layout.misc_overscroll_demo, null, false);
|
||||
|
||||
View textView = fragmentView.findViewById(R.id.demo_text);
|
||||
OverScrollDecoratorHelper.setUpStaticOverScroll(textView, OverScrollDecoratorHelper.ORIENTATION_HORIZONTAL);
|
||||
|
||||
View imageView = fragmentView.findViewById(R.id.demo_image);
|
||||
OverScrollDecoratorHelper.setUpStaticOverScroll(imageView, OverScrollDecoratorHelper.ORIENTATION_VERTICAL);
|
||||
|
||||
mChrono = (Chronometer) fragmentView.findViewById(R.id.demo_chronometer);
|
||||
if (savedInstanceState != null) {
|
||||
mChrono.setBase(savedInstanceState.getLong(CHRONO_TIME_SAVE_ID));
|
||||
}
|
||||
OverScrollDecoratorHelper.setUpStaticOverScroll(mChrono, OverScrollDecoratorHelper.ORIENTATION_HORIZONTAL);
|
||||
mChrono.start();
|
||||
|
||||
return fragmentView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putLong(CHRONO_TIME_SAVE_ID, mChrono.getBase());
|
||||
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package me.everything.overscrolldemo.view;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
import me.everything.android.ui.overscroll.OverScrollDecoratorHelper;
|
||||
import me.everything.overscrolldemo.R;
|
||||
|
||||
public class NestedScrollViewDemoFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
final ScrollView rootView = (ScrollView) inflater.inflate(R.layout.nested_scrollview_demo, null, false);
|
||||
OverScrollDecoratorHelper.setUpOverScroll(rootView);
|
||||
return rootView;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
package me.everything.overscrolldemo.view;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import me.everything.android.ui.overscroll.IOverScrollDecor;
|
||||
import me.everything.android.ui.overscroll.IOverScrollStateListener;
|
||||
import me.everything.android.ui.overscroll.IOverScrollUpdateListener;
|
||||
import me.everything.android.ui.overscroll.OverScrollDecoratorHelper;
|
||||
import me.everything.android.ui.overscroll.VerticalOverScrollBounceEffectDecorator;
|
||||
import me.everything.android.ui.overscroll.adapters.RecyclerViewOverScrollDecorAdapter;
|
||||
import me.everything.overscrolldemo.R;
|
||||
import me.everything.overscrolldemo.control.DemoContentHelper;
|
||||
|
||||
import static me.everything.android.ui.overscroll.IOverScrollState.*;
|
||||
|
||||
public class RecyclerViewDemoFragment extends Fragment {
|
||||
|
||||
private TextView mHorizScrollMeasure;
|
||||
private TextView mVertScrollMeasure;
|
||||
|
||||
private IOverScrollDecor mHorizOverScrollEffect;
|
||||
private IOverScrollDecor mVertOverScrollEffect;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
View fragmentView = inflater.inflate(R.layout.recyclerview_overscroll_demo, null, false);
|
||||
|
||||
mHorizScrollMeasure = (TextView) fragmentView.findViewById(R.id.horizontal_scroll_measure);
|
||||
mVertScrollMeasure = (TextView) fragmentView.findViewById(R.id.vertical_scroll_measure);
|
||||
|
||||
initHorizontalRecyclerView((RecyclerView) fragmentView.findViewById(R.id.horizontal_recycler_view));
|
||||
initVerticalRecyclerView((RecyclerView) fragmentView.findViewById(R.id.vertical_recycler_view));
|
||||
return fragmentView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
final MenuItem detachMenuItem = menu.add("Detach over-scroll").setVisible(true);
|
||||
final MenuItem attachMenuItem = menu.add("Attach over-scroll").setVisible(false);
|
||||
detachMenuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
detachMenuItem.setVisible(false);
|
||||
attachMenuItem.setVisible(true);
|
||||
mHorizOverScrollEffect.detach();
|
||||
mVertOverScrollEffect.detach();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
attachMenuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
detachMenuItem.setVisible(true);
|
||||
attachMenuItem.setVisible(false);
|
||||
initHorizontalRecyclerView((RecyclerView) getView().findViewById(R.id.horizontal_recycler_view));
|
||||
initVerticalRecyclerView((RecyclerView) getView().findViewById(R.id.vertical_recycler_view));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
private void initHorizontalRecyclerView(RecyclerView recyclerView) {
|
||||
LayoutInflater appInflater = LayoutInflater.from(getActivity().getApplicationContext());
|
||||
RecyclerView.Adapter adapter = new DemoRecyclerAdapterHorizontal(DemoContentHelper.getSpectrumItems(getResources()), appInflater);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false));
|
||||
|
||||
// Apply over-scroll in 'standard form' - i.e. using the helper.
|
||||
mHorizOverScrollEffect = OverScrollDecoratorHelper.setUpOverScroll(recyclerView, OverScrollDecoratorHelper.ORIENTATION_HORIZONTAL);
|
||||
|
||||
// Over-scroll listeners can be applied in standard form as well.
|
||||
mHorizOverScrollEffect.setOverScrollUpdateListener(new IOverScrollUpdateListener() {
|
||||
@Override
|
||||
public void onOverScrollUpdate(IOverScrollDecor decor, int state, float offset) {
|
||||
mHorizScrollMeasure.setText(String.valueOf((int) offset));
|
||||
}
|
||||
});
|
||||
mHorizOverScrollEffect.setOverScrollStateListener(new IOverScrollStateListener() {
|
||||
|
||||
private final int mDragColorLeft = getResources().getColor(android.R.color.holo_purple);
|
||||
private final int mBounceBackColorLeft = getResources().getColor(android.R.color.holo_blue_light);
|
||||
private final int mDragColorRight = getResources().getColor(android.R.color.holo_red_light);
|
||||
private final int mBounceBackColorRight = getResources().getColor(android.R.color.holo_orange_dark);
|
||||
private final int mClearColor = mHorizScrollMeasure.getCurrentTextColor();
|
||||
|
||||
@Override
|
||||
public void onOverScrollStateChange(IOverScrollDecor decor, int oldState, int newState) {
|
||||
if (newState == STATE_DRAG_START_SIDE) {
|
||||
mHorizScrollMeasure.setTextColor(mDragColorLeft);
|
||||
} else if (newState == STATE_DRAG_END_SIDE) {
|
||||
mHorizScrollMeasure.setTextColor(mDragColorRight);
|
||||
} else if (newState == STATE_BOUNCE_BACK) {
|
||||
mHorizScrollMeasure.setTextColor((oldState == STATE_DRAG_START_SIDE) ? mBounceBackColorLeft : mBounceBackColorRight);
|
||||
} else {
|
||||
mHorizScrollMeasure.setTextColor(mClearColor);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initVerticalRecyclerView(RecyclerView recyclerView) {
|
||||
LayoutInflater appInflater = LayoutInflater.from(getActivity().getApplicationContext());
|
||||
final DemoRecyclerAdapterBase adapter = new DemoRecyclerAdapterVertical(new ArrayList<>(DemoContentHelper.getReverseSpectrumItems(getResources())), appInflater);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
|
||||
|
||||
// Set-up of recycler-view's native item swiping.
|
||||
ItemTouchHelper.Callback itemTouchHelperCallback = new ItemTouchHelper.Callback() {
|
||||
@Override
|
||||
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||
return makeMovementFlags(0, ItemTouchHelper.RIGHT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
AlertDialog dialog = new AlertDialog.Builder(getActivity())
|
||||
.setTitle("Item swiping is supported!")
|
||||
.setMessage("Recycler-view's native item swiping and the over-scrolling effect can co-exist! But, to get them to work WELL -- please apply the effect using the dedicated helper method!")
|
||||
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
})
|
||||
.create();
|
||||
dialog.show();
|
||||
}
|
||||
};
|
||||
|
||||
// Apply over-scroll in 'advanced form' - i.e. create an instance manually.
|
||||
mVertOverScrollEffect = new VerticalOverScrollBounceEffectDecorator(new RecyclerViewOverScrollDecorAdapter(recyclerView, itemTouchHelperCallback));
|
||||
|
||||
// Over-scroll listeners are applied here via the mVertOverScrollEffect explicitly.
|
||||
mVertOverScrollEffect.setOverScrollUpdateListener(new IOverScrollUpdateListener() {
|
||||
@Override
|
||||
public void onOverScrollUpdate(IOverScrollDecor decor, int state, float offset) {
|
||||
mVertScrollMeasure.setText(String.valueOf((int) offset));
|
||||
}
|
||||
});
|
||||
mVertOverScrollEffect.setOverScrollStateListener(new IOverScrollStateListener() {
|
||||
private final int mDragColorTop = getResources().getColor(android.R.color.holo_red_light);
|
||||
private final int mBounceBackColorTop = getResources().getColor(android.R.color.holo_orange_dark);
|
||||
private final int mDragColorBottom = getResources().getColor(android.R.color.holo_purple);
|
||||
private final int mBounceBackColorBottom = getResources().getColor(android.R.color.holo_blue_light);
|
||||
private final int mClearColor = mHorizScrollMeasure.getCurrentTextColor();
|
||||
|
||||
@Override
|
||||
public void onOverScrollStateChange(IOverScrollDecor decor, int oldState, int newState) {
|
||||
if (newState == STATE_DRAG_START_SIDE) {
|
||||
mVertScrollMeasure.setTextColor(mDragColorTop);
|
||||
} else if (newState == STATE_DRAG_END_SIDE) {
|
||||
mVertScrollMeasure.setTextColor(mDragColorBottom);
|
||||
} else if (newState == STATE_BOUNCE_BACK) {
|
||||
mVertScrollMeasure.setTextColor(oldState == STATE_DRAG_START_SIDE ? mBounceBackColorTop : mBounceBackColorBottom);
|
||||
} else {
|
||||
mVertScrollMeasure.setTextColor(mClearColor);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package me.everything.overscrolldemo.view;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import me.everything.android.ui.overscroll.OverScrollDecoratorHelper;
|
||||
import me.everything.overscrolldemo.R;
|
||||
import me.everything.overscrolldemo.control.DemoContentHelper;
|
||||
|
||||
public class RecyclerViewStaggeredGridDemoFragment extends Fragment {
|
||||
|
||||
private static final int GRID_SPAN_COUNT = 2;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View fragmentView = inflater.inflate(R.layout.recyclerview_stgrid_overscroll_demo, null, false);
|
||||
initVerticalRecyclerView((RecyclerView) fragmentView.findViewById(R.id.vertical_recycler_view));
|
||||
return fragmentView;
|
||||
}
|
||||
|
||||
private void initVerticalRecyclerView(RecyclerView recyclerView) {
|
||||
LayoutInflater appInflater = LayoutInflater.from(getActivity().getApplicationContext());
|
||||
final DemoRecyclerAdapterBase adapter = new DemoRecyclerAdapterVertical(new ArrayList<>(DemoContentHelper.getReverseSpectrumItems(getResources())), appInflater);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(GRID_SPAN_COUNT, StaggeredGridLayoutManager.VERTICAL));
|
||||
OverScrollDecoratorHelper.setUpOverScroll(recyclerView, OverScrollDecoratorHelper.ORIENTATION_VERTICAL);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package me.everything.overscrolldemo.view;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
import me.everything.android.ui.overscroll.OverScrollDecoratorHelper;
|
||||
import me.everything.overscrolldemo.R;
|
||||
|
||||
public class ScrollViewDemoFragment extends Fragment {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View fragmentView = inflater.inflate(R.layout.scrollview_overscroll_demo, null, false);
|
||||
initHorizontalScrollView((HorizontalScrollView) fragmentView.findViewById(R.id.horizontal_scroll_view));
|
||||
initVerticalScrollView((ScrollView) fragmentView.findViewById(R.id.vertical_scroll_view));
|
||||
return fragmentView;
|
||||
}
|
||||
|
||||
private void initHorizontalScrollView(HorizontalScrollView scrollView) {
|
||||
OverScrollDecoratorHelper.setUpOverScroll(scrollView);
|
||||
}
|
||||
|
||||
private void initVerticalScrollView(ScrollView scrollView) {
|
||||
OverScrollDecoratorHelper.setUpOverScroll(scrollView);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package me.everything.overscrolldemo.view;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.everything.android.ui.overscroll.OverScrollDecoratorHelper;
|
||||
import me.everything.overscrolldemo.R;
|
||||
import me.everything.overscrolldemo.control.DemoContentHelper;
|
||||
import me.everything.overscrolldemo.control.DemoItem;
|
||||
|
||||
public class ViewPagerDemoFragment extends Fragment {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.viewpager_overscroll_demo,null,false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
initHorizontalViewPager(DemoContentHelper.getSpectrumItems(getResources()), ((ViewPager) view.findViewById(R.id.view_pager)));
|
||||
}
|
||||
|
||||
private void initHorizontalViewPager(List<DemoItem> items, ViewPager viewPager) {
|
||||
|
||||
ViewPagerAdapter adapter = new ViewPagerAdapter(items);
|
||||
viewPager.setAdapter(adapter);
|
||||
OverScrollDecoratorHelper.setUpOverScroll(viewPager);
|
||||
}
|
||||
|
||||
public static class ViewPagerAdapter extends PagerAdapter{
|
||||
|
||||
private List<DemoItem> items;
|
||||
public ViewPagerAdapter(List<DemoItem> items){
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(View view, Object object) {
|
||||
return view == object;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Object instantiateItem(ViewGroup container, int position) {
|
||||
TextView textView = new TextView(container.getContext());
|
||||
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
textView.setText(items.get(position).getColorName());
|
||||
textView.setBackgroundColor(items.get(position).getColor());
|
||||
textView.setGravity(Gravity.CENTER);
|
||||
container.addView(textView);
|
||||
return textView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
container.removeView((View) object);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:interpolator/linear"
|
||||
android:valueFrom="0.0"
|
||||
android:valueTo="1.0"
|
||||
android:propertyName="alpha"
|
||||
android:duration="500"
|
||||
/>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:interpolator/linear"
|
||||
android:valueFrom="1.0"
|
||||
android:valueTo="0.0"
|
||||
android:propertyName="alpha"
|
||||
android:duration="80"
|
||||
/>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:color="@android:color/white"
|
||||
android:state_checked="true"
|
||||
/>
|
||||
<item android:color="@android:color/darker_gray"/>
|
||||
</selector>
|
||||
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 285 B |
|
After Width: | Height: | Size: 219 B |
|
After Width: | Height: | Size: 323 B |
|
After Width: | Height: | Size: 620 B |
|
After Width: | Height: | Size: 329 B |
|
After Width: | Height: | Size: 451 B |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 279 B |
|
After Width: | Height: | Size: 171 B |
|
After Width: | Height: | Size: 222 B |
|
After Width: | Height: | Size: 385 B |
|
After Width: | Height: | Size: 300 B |
|
After Width: | Height: | Size: 240 B |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 311 B |
|
After Width: | Height: | Size: 191 B |
|
After Width: | Height: | Size: 253 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 353 B |
|
After Width: | Height: | Size: 404 B |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 574 B |
|
After Width: | Height: | Size: 239 B |
|
After Width: | Height: | Size: 390 B |
|
After Width: | Height: | Size: 804 B |
|
After Width: | Height: | Size: 598 B |
|
After Width: | Height: | Size: 680 B |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 809 B |
|
After Width: | Height: | Size: 265 B |
|
After Width: | Height: | Size: 460 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 828 B |
|
After Width: | Height: | Size: 965 B |
@@ -0,0 +1,10 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle" >
|
||||
<gradient
|
||||
android:startColor="@android:color/holo_red_dark"
|
||||
android:centerColor="@android:color/holo_green_light"
|
||||
android:endColor="@android:color/holo_blue_dark"
|
||||
android:type="linear"
|
||||
android:angle="135"
|
||||
/>
|
||||
</shape>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:drawable="@android:color/darker_gray"
|
||||
android:state_checked="true"
|
||||
/>
|
||||
</selector>
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.drawerlayout.widget.DrawerLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:openDrawer="start"
|
||||
>
|
||||
|
||||
<include layout="@layout/activity_overscroll_demo_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
|
||||
<com.google.android.material.navigation.NavigationView
|
||||
android:id="@+id/drawer_nav"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
|
||||
app:headerLayout="@layout/drawer_header_overscroll_demo"
|
||||
app:menu="@menu/activity_overscroll_demo_drawer_items"
|
||||
|
||||
app:itemBackground="@drawable/drawer_items_bkg"
|
||||
/>
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".OverscrollDemo"
|
||||
>
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/app_bar"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:theme="@style/AppTheme.AppBarOverlay"
|
||||
>
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fragment_placeholder"
|
||||
android:layout_below="@id/app_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/nav_header_height"
|
||||
android:background="@color/colorPrimary"
|
||||
android:padding="16dp"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="fill_horizontal"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:layout_height="64dp"
|
||||
android:layout_width="64dp"
|
||||
android:src="@drawable/app_icon"
|
||||
android:layout_gravity="center_vertical"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="16dp"
|
||||
>
|
||||
<TextView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/drawer_title"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
|
||||
android:textSize="18dp"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/drawer_subtitle"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/color_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="200dp"
|
||||
android:textSize="30dp"
|
||||
android:textColor="@android:color/black"
|
||||
android:gravity="center"
|
||||
/>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:textSize="@dimen/default_label_size"
|
||||
android:text="@string/vert_drag_label"
|
||||
android:lines="1"
|
||||
/>
|
||||
<!--
|
||||
When over-scrolling is applied over views that don't stretch over the entire vertical region,
|
||||
an artificial parent must be introduced so that bounds are clipped while over-scrolling is
|
||||
in effect.
|
||||
-->
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:layout_weight="1"
|
||||
>
|
||||
<GridView
|
||||
android:id="@+id/grid_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:numColumns="auto_fit"
|
||||
android:stretchMode="columnWidth"
|
||||
android:verticalSpacing="10dp"
|
||||
android:horizontalSpacing="10dp"
|
||||
android:gravity="center"
|
||||
/>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/color_name"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="100dp"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingBottom="20dp"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="18dp"
|
||||
android:textColor="@android:color/black"
|
||||
android:gravity="center"
|
||||
/>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/color_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingBottom="20dp"
|
||||
android:textSize="40dp"
|
||||
android:gravity="center"
|
||||
android:clickable="true"
|
||||
android:background="@android:color/black"
|
||||
/>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:textSize="@dimen/default_label_size"
|
||||
android:text="@string/vert_drag_label"
|
||||
android:lines="1"
|
||||
/>
|
||||
<!--
|
||||
When over-scrolling is applied over views that don't stretch over the entire vertical region,
|
||||
an artificial parent must be introduced so that bounds are clipped while over-scrolling is
|
||||
in effect.
|
||||
-->
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:layout_weight="1"
|
||||
>
|
||||
<ListView
|
||||
android:id="@+id/list_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/demo_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:clickable="true"
|
||||
android:text="Practically any clickable widget can be over-scrolled.\nTry it!"
|
||||
android:textSize="30sp"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
>
|
||||
<ImageView
|
||||
android:id="@+id/demo_image"
|
||||
android:layout_width="128dp"
|
||||
android:layout_height="128dp"
|
||||
android:layout_gravity="center"
|
||||
android:clickable="true"
|
||||
android:background="@drawable/app_icon"
|
||||
/>
|
||||
</FrameLayout>
|
||||
|
||||
<Chronometer
|
||||
android:id="@+id/demo_chronometer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center"
|
||||
android:clickable="true"
|
||||
android:textSize="30sp"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="none"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal"
|
||||
>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/nested_scrollview_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="180dp"
|
||||
android:padding="14dp"
|
||||
android:paddingTop="0dp"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/nested_scrollview_text"
|
||||
android:textSize="19sp"
|
||||
android:textStyle="bold"
|
||||
/>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/horizontal_recycler_view_header"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="left"
|
||||
android:textSize="@dimen/default_label_size"
|
||||
android:text="@string/horiz_drag_label"
|
||||
android:lines="1"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/horizontal_scroll_measure"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:textSize="@dimen/default_subtitle_size"
|
||||
android:text="0"
|
||||
android:textStyle="bold"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/horizontal_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:layout_weight="3"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/vertical_recycler_view_header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="left"
|
||||
android:textSize="@dimen/default_label_size"
|
||||
android:text="@string/vert_drag_label"
|
||||
android:lines="1"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/vertical_scroll_measure"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:textSize="@dimen/default_subtitle_size"
|
||||
android:text="0"
|
||||
android:textStyle="bold"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<!--
|
||||
When over-scrolling is applied over views that don't stretch though the full vertical region,
|
||||
an artificial parent must be introduced so that bounds are clipped while over-scrolling is
|
||||
in effect.
|
||||
-->
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:paddingTop="10dp"
|
||||
android:layout_weight="7"
|
||||
>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/vertical_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:id="@+id/vertical_recycler_view_header"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:textSize="@dimen/default_label_size"
|
||||
android:text="@string/vert_drag_label"
|
||||
android:lines="1"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<!--
|
||||
When over-scrolling is applied over views that don't stretch though the full vertical region,
|
||||
an artificial parent must be introduced so that bounds are clipped while over-scrolling is
|
||||
in effect.
|
||||
-->
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="10dp"
|
||||
>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/vertical_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginRight="20dp"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:layout_height="64dp"
|
||||
android:layout_width="64dp"
|
||||
android:src="@drawable/app_icon"
|
||||
android:layout_gravity="center"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="EverythingMe"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:textSize="@dimen/default_label_size"
|
||||
android:text="@string/horiz_drag_label"
|
||||
android:lines="1"
|
||||
/>
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/horizontal_scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:paddingTop="10dp"
|
||||
android:layout_weight="3"
|
||||
>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<include layout="@layout/scrollview_horizontal_item"/>
|
||||
<include layout="@layout/scrollview_horizontal_item"/>
|
||||
<include layout="@layout/scrollview_horizontal_item"/>
|
||||
<include layout="@layout/scrollview_horizontal_item"/>
|
||||
<include layout="@layout/scrollview_horizontal_item"/>
|
||||
<include layout="@layout/scrollview_horizontal_item"/>
|
||||
<include layout="@layout/scrollview_horizontal_item"/>
|
||||
<include layout="@layout/scrollview_horizontal_item"/>
|
||||
<include layout="@layout/scrollview_horizontal_item"/>
|
||||
<include layout="@layout/scrollview_horizontal_item"/>
|
||||
</LinearLayout>
|
||||
</HorizontalScrollView>
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:textSize="@dimen/default_label_size"
|
||||
android:text="@string/vert_drag_label"
|
||||
android:lines="1"
|
||||
/>
|
||||
|
||||
<!--
|
||||
When over-scrolling is applied over views that don't stretch over the full vertical region,
|
||||
an artificial parent must be introduced so that bounds are clipped while over-scrolling is
|
||||
in effect.
|
||||
-->
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:paddingTop="10dp"
|
||||
android:layout_weight="7"
|
||||
>
|
||||
<ScrollView
|
||||
android:id="@+id/vertical_scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
>
|
||||
>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
<include layout="@layout/scrollview_vertical_item"/>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="10dp"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:layout_height="64dp"
|
||||
android:layout_width="64dp"
|
||||
android:src="@drawable/app_icon"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:text="EverythingMe"
|
||||
android:textSize="21dp"
|
||||
android:gravity="left|center_vertical"
|
||||
android:layout_gravity="center"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:showIn="@layout/app_bar_overscroll_demo"
|
||||
tools:context=".OverscrollDemo"
|
||||
>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
>
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/color_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingBottom="20dp"
|
||||
android:textSize="40dp"
|
||||
android:textColor="@android:color/black"
|
||||
android:gravity="center"
|
||||
/>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/view_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<group
|
||||
android:checkableBehavior="single">
|
||||
|
||||
<item
|
||||
android:id="@+id/drawer_item_recyclerview_demo"
|
||||
android:icon="@drawable/ic_recycler"
|
||||
android:title="RecyclerView Demo"
|
||||
android:checked="true"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/drawer_item_recyclerview_staggered_grid_demo"
|
||||
android:icon="@drawable/ic_recycler"
|
||||
android:title="RecyclerView - St.Grid Demo"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/drawer_item_gridview_demo"
|
||||
android:icon="@drawable/ic_grid"
|
||||
android:title="GridView Demo"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/drawer_item_listview_demo"
|
||||
android:icon="@drawable/ic_list"
|
||||
android:title="ListView Demo"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/drawer_item_scrollview_demo"
|
||||
android:icon="@drawable/ic_scroller"
|
||||
android:title="ScrollView Demo"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/drawer_item_viewpager_demo"
|
||||
android:icon="@drawable/ic_view_pager"
|
||||
android:title="ViewPager Demo"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/drawer_item_nested_scrollview_demo"
|
||||
android:title="NestedScrollView Demo"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/drawer_item_misc_demo"
|
||||
android:icon="@drawable/ic_misc"
|
||||
android:title="Misc-Views Demo"
|
||||
/>
|
||||
|
||||
</group>
|
||||
|
||||
</menu>
|
||||
@@ -0,0 +1,8 @@
|
||||
<resources>>
|
||||
<style name="AppTheme.NoActionBar">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,6 @@
|
||||
<resources>
|
||||
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
|
||||
(such as screen margins) for screens with more than 820dp of available width. This
|
||||
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
|
||||
<dimen name="activity_horizontal_margin">64dp</dimen>
|
||||
</resources>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">@android:color/holo_orange_light</color>
|
||||
<color name="colorPrimaryDark">@android:color/holo_orange_dark</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
|
||||
<color name="spectrum_cyan">#00e0e0</color>
|
||||
<color name="spectrum_yellow">#f0e000</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,9 @@
|
||||
<resources>
|
||||
<dimen name="nav_header_vertical_spacing">16dp</dimen>
|
||||
<dimen name="nav_header_height">140dp</dimen>
|
||||
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
<dimen name="default_label_size">26sp</dimen>
|
||||
<dimen name="default_subtitle_size">22sp</dimen>
|
||||
</resources>
|
||||
@@ -0,0 +1,23 @@
|
||||
<resources>
|
||||
<string name="app_name">OverscrollDemo</string>
|
||||
|
||||
<string name="drawer_title">Over-Scroll Demo App</string>
|
||||
<string name="drawer_subtitle">EverythingMe</string>
|
||||
|
||||
<string name="navigation_drawer_open">Open navigation drawer</string>
|
||||
<string name="navigation_drawer_close">Close navigation drawer</string>
|
||||
|
||||
<string name="grid_view_demo_title">GridView Over-Scroll Demo</string>
|
||||
<string name="list_view_demo_title">ListView Over-Scroll Demo</string>
|
||||
<string name="recycler_view_demo_title">RecyclerView Over-Scroll Demo</string>
|
||||
<string name="recycler_view_staggered_grid_demo_title">RecyclerView St.Grid Over-Scroll Demo</string>
|
||||
<string name="scroll_view_demo_title">ScrollView Over-Scroll Demo</string>
|
||||
<string name="viewpager_demo_title">ViewPager Over-Scroll Demo</string>
|
||||
<string name="nested_scrollview_demo_title">NestedScrollView Over-Scroll Demo</string>
|
||||
<string name="misc_views_demo_title">Misc. Over-Scroll Demo</string>
|
||||
<string name="nested_scrollview_text">This text box is scrollable thanks to being situated inside a nested scroll view. That makes it scrollable regardless of the scrolling of the content of the entire screen, which can be scrolled independently.\nThe point here is to demonstrate how the over-scroll effect can work in the presence of nested scroll-views, provided it is applied over the parent (root) view, regardless of having inner nested scroll-views as children.\nIn this demo, the root view is merely a ScrollView, and therefore applying the effect over it is straightforward (i.e. using the OverScrollHelper).</string>
|
||||
|
||||
<string name="horiz_drag_label">⇔ Drag Horizontally</string>
|
||||
<string name="vert_drag_label">⇳ Drag Vertically</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,17 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
<style name="AppTheme.NoActionBar">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
</style>
|
||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,26 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext {
|
||||
_isOverscrollDecor = true
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.0.2'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
# Default value: -Xmx10248m -XX:MaxPermSize=256m
|
||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
@@ -0,0 +1,6 @@
|
||||
#Mon Mar 02 14:56:48 WIB 2026
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,33 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
namespace 'me.everything.android.ui.overscroll'
|
||||
compileSdk 33
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 33
|
||||
versionCode 1
|
||||
versionName '1.0'
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.recyclerview:recyclerview:1.3.2'
|
||||
implementation 'androidx.viewpager:viewpager:1.0.0'
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'org.mockito:mockito-core:3.1.0'
|
||||
testImplementation 'org.robolectric:robolectric:4.3.1'
|
||||
}
|
||||
|
||||
// Enable publishing
|
||||
if (rootProject.hasProperty('_isOverscrollDecor')) {
|
||||
apply from: './publishing.gradle'
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Based on https://stackoverflow.com/a/42160584/453052
|
||||
|
||||
project.ext.buildPomXmlDependencies = { pom, configurations ->
|
||||
pom.withXml {
|
||||
final rootNode = asNode().appendNode('dependencies')
|
||||
addConfigurationDependencies(rootNode, configurations.api, 'compile')
|
||||
addConfigurationDependencies(rootNode, configurations.compile, 'compile')
|
||||
addConfigurationDependencies(rootNode, configurations.implementation, 'runtime')
|
||||
}
|
||||
}
|
||||
|
||||
private static def addConfigurationDependencies(rootNode, Configuration configuration, String scope) {
|
||||
configuration.dependencies.each { dep -> addChildDependency(rootNode, dep, scope) }
|
||||
}
|
||||
|
||||
private static def addChildDependency(rootNode, Dependency dep, String scope) {
|
||||
if (dep.group == null || dep.version == null || dep.name == null || dep.name == "unspecified")
|
||||
return
|
||||
|
||||
final childNode = rootNode.appendNode('dependency')
|
||||
childNode.appendNode('groupId', dep.group)
|
||||
childNode.appendNode('artifactId', dep.name)
|
||||
childNode.appendNode('version', dep.version)
|
||||
childNode.appendNode('scope', scope)
|
||||
|
||||
if (!dep.transitive) {
|
||||
// If this dependency is transitive, we should force exclude all its dependencies them from the POM
|
||||
final exclusionNode = childNode.appendNode('exclusions').appendNode('exclusion')
|
||||
exclusionNode.appendNode('groupId', '*')
|
||||
exclusionNode.appendNode('artifactId', '*')
|
||||
} else if (!dep.properties.excludeRules.empty) {
|
||||
// Otherwise add specified exclude rules
|
||||
final exclusionNode = childNode.appendNode('exclusions').appendNode('exclusion')
|
||||
dep.properties.excludeRules.each { ExcludeRule rule ->
|
||||
exclusionNode.appendNode('groupId', rule.group ?: '*')
|
||||
exclusionNode.appendNode('artifactId', rule.module ?: '*')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'signing'
|
||||
apply from: './publish-pom.gradle'
|
||||
|
||||
String TARGET_MAVEN_CENTRAL_URL = 'https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/'
|
||||
|
||||
List DEVELOPERS = [
|
||||
[name: 'd4vidi', email: 'amit.d4vidi@gmail.com'],
|
||||
]
|
||||
|
||||
String _sonatypeUsername = 'd4vidi'
|
||||
String _sonatypePassword = System.getProperty('sonatypePassword')
|
||||
String _versionName = System.getProperty('version')
|
||||
String _mavenRepoUrl = TARGET_MAVEN_CENTRAL_URL
|
||||
Map _mavenCredentials = [
|
||||
username: _sonatypeUsername,
|
||||
password: _sonatypePassword,
|
||||
]
|
||||
def _selectedVariant = null
|
||||
|
||||
def onPrePublish = {
|
||||
assertDefined(_versionName, "Publishing: Version not specified (run 'gradle publish' with a -Dversion=1.2.3 argument)")
|
||||
assertDefined(_sonatypePassword, "Publishing: Please specify the password to use for sonatype (run 'gradle publish' with a -DsonatypePassword=<pw> argument)")
|
||||
logger.lifecycle("Publishing is now in session! 📣\n Version: $_versionName\n Target URL: ${_mavenRepoUrl}\n Build-variant: '${_selectedVariant.name}'")
|
||||
}
|
||||
|
||||
def declareArchive = { target ->
|
||||
project.artifacts {
|
||||
archives target
|
||||
}
|
||||
}
|
||||
|
||||
// Running from Gradle tab in IDE would create liboverscroll/build/libs/liboverscroll-sources.jar
|
||||
task sourcesJar(type: Jar) {
|
||||
from android.sourceSets.main.java.srcDirs
|
||||
classifier = 'sources'
|
||||
}
|
||||
|
||||
task javadoc(type: Javadoc) {
|
||||
failOnError false
|
||||
source = android.sourceSets.main.java.srcDirs
|
||||
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
|
||||
}
|
||||
|
||||
// Running from Gradle tab in IDE would create liboverscroll/build/libs/liboverscroll-javadoc.jar
|
||||
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||
classifier = 'javadoc'
|
||||
from javadoc.destinationDir
|
||||
}
|
||||
|
||||
/*
|
||||
* Signing configuration
|
||||
* https://docs.gradle.org/current/userguide/signing_plugin.html
|
||||
*/
|
||||
|
||||
// Tell signing task to sign everything current and future we set as a project archive...
|
||||
signing {
|
||||
sign configurations.archives
|
||||
}
|
||||
|
||||
/*
|
||||
* Plumbing work for actually having the publishing task work properly, if executed
|
||||
*/
|
||||
|
||||
project.afterEvaluate {
|
||||
project.tasks.all { Task task ->
|
||||
android.libraryVariants.all { variant ->
|
||||
String variantName = variant.name.capitalize()
|
||||
if (task.name == "publishMaven${variantName}AarPublicationToMavenRepository") {
|
||||
task.dependsOn "assemble${variantName}"
|
||||
task.dependsOn project.tasks.signArchives
|
||||
task.doFirst {
|
||||
onPrePublish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Publishing configuration
|
||||
*/
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
url _mavenRepoUrl
|
||||
if (_mavenCredentials != null) {
|
||||
credentials {
|
||||
username _mavenCredentials.username
|
||||
password _mavenCredentials.password
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
publications {
|
||||
android.libraryVariants.all { variant ->
|
||||
if (isReleaseVariant(variant)) {
|
||||
_selectedVariant = variant
|
||||
|
||||
String variantNameCapitalized = variant.name.capitalize()
|
||||
|
||||
"maven${variantNameCapitalized}Aar"(MavenPublication) {
|
||||
groupId 'io.github.everythingme'
|
||||
artifactId 'overscroll-decor-android'
|
||||
version "$_versionName"
|
||||
|
||||
// Register built .aar as published artifact (as a file, explicitly)
|
||||
variant.outputs.forEach { output ->
|
||||
artifact output.outputFile
|
||||
|
||||
// Also register as an archive-artifact, for signing (via equivalent task's output)
|
||||
declareArchive project.tasks["bundle${variantNameCapitalized}Aar"]
|
||||
}
|
||||
|
||||
// Register sources, javadoc as published artifacts (via equivalent tasks' output)
|
||||
artifact sourcesJar
|
||||
artifact javadocJar
|
||||
|
||||
// Also register source, javadoc as archive-artifacts, for signing
|
||||
declareArchive sourcesJar
|
||||
declareArchive javadocJar
|
||||
|
||||
// Add package metadata to the .pom
|
||||
pom {
|
||||
name = 'Overscroll-Decor'
|
||||
description = 'iOS-like over-scrolling effect for Android'
|
||||
url = 'https://github.com/EverythingMe/overscroll-decor'
|
||||
packaging 'aar' // Oh so important - or apps would ignore our code!!!!!
|
||||
scm {
|
||||
connection = 'scm:git:git://github.com/EverythingMe/overscroll-decor'
|
||||
developerConnection = 'scm:git:git@github.com/EverythingMe/overscroll-decor.git'
|
||||
url = 'https://github.com/EverythingMe/overscroll-decor'
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name = 'BSD-2'
|
||||
url = 'https://github.com/EverythingMe/overscroll-decor/blob/master/LICENSE'
|
||||
}
|
||||
}
|
||||
developers {
|
||||
DEVELOPERS.each { d ->
|
||||
developer {
|
||||
name = d.name
|
||||
email = d.email
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add dependencies to the .pom
|
||||
buildPomXmlDependencies(pom, configurations)
|
||||
|
||||
// Register pom.xml's signature file (pom.xml.asc) as published artifact
|
||||
// Note: this is done manually, instead of registering the pom as an archived artifact
|
||||
pom.withXml {
|
||||
def pomFile = file("${project.buildDir}/generated-pom.xml")
|
||||
writeTo(pomFile) // Need to force-write so as to have the signature generated over the finalized content
|
||||
|
||||
def pomAscFile = signing.sign(pomFile).signatureFiles[0]
|
||||
artifact(pomAscFile) {
|
||||
classifier = null
|
||||
extension = 'pom.asc'
|
||||
}
|
||||
}
|
||||
|
||||
// Register all artifacts we've previously registered as archives (i.e. .jar.asc's, .aar.asc's) as published artifacts.
|
||||
// Note: this relies on preregistering the equivalent generator-tasks as archive artifacts
|
||||
// inside a project.artifacts { ... } clause.
|
||||
project.tasks.signArchives.signatureFiles.each {
|
||||
artifact(it) {
|
||||
def matcherSrcDocs = (it.file =~ /-(sources|javadoc)\.jar\.asc$/)
|
||||
def matcherAAR = (it.file =~ /\.aar\.asc$/)
|
||||
if (matcherSrcDocs.find()) {
|
||||
classifier = matcherSrcDocs.group(1)
|
||||
extension = 'jar.asc'
|
||||
} else if (matcherAAR.find()) {
|
||||
classifier = null
|
||||
extension = 'aar.asc'
|
||||
} else {
|
||||
classifier = null
|
||||
extension = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Utils
|
||||
*/
|
||||
|
||||
private static def isReleaseVariant(variant) {
|
||||
return variant.buildType.name == 'release'
|
||||
}
|
||||
|
||||
private static def assertDefined(target, message) {
|
||||
if (target == null) {
|
||||
throw new IllegalArgumentException(message)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package me.everything.android.ui.overscroll;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import me.everything.android.ui.overscroll.adapters.IOverScrollDecoratorAdapter;
|
||||
|
||||
/**
|
||||
* A concrete implementation of {@link OverScrollBounceEffectDecoratorBase} for a horizontal orientation.
|
||||
*/
|
||||
public class HorizontalOverScrollBounceEffectDecorator extends OverScrollBounceEffectDecoratorBase {
|
||||
|
||||
protected static class MotionAttributesHorizontal extends MotionAttributes {
|
||||
|
||||
public boolean init(View view, MotionEvent event) {
|
||||
|
||||
// We must have history available to calc the dx. Normally it's there - if it isn't temporarily,
|
||||
// we declare the event 'invalid' and expect it in consequent events.
|
||||
if (event.getHistorySize() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allow for counter-orientation-direction operations (e.g. item swiping) to run fluently.
|
||||
final float dy = event.getY(0) - event.getHistoricalY(0, 0);
|
||||
final float dx = event.getX(0) - event.getHistoricalX(0, 0);
|
||||
if (Math.abs(dx) < Math.abs(dy)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mAbsOffset = view.getTranslationX();
|
||||
mDeltaOffset = dx;
|
||||
mDir = mDeltaOffset > 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class AnimationAttributesHorizontal extends AnimationAttributes {
|
||||
|
||||
public AnimationAttributesHorizontal() {
|
||||
mProperty = View.TRANSLATION_X;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(View view) {
|
||||
mAbsOffset = view.getTranslationX();
|
||||
mMaxOffset = view.getWidth();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* C'tor, creating the effect with default arguments:
|
||||
* <br/>Touch-drag ratio in 'forward' direction will be set to DEFAULT_TOUCH_DRAG_MOVE_RATIO_FWD.
|
||||
* <br/>Touch-drag ratio in 'backwards' direction will be set to DEFAULT_TOUCH_DRAG_MOVE_RATIO_BCK.
|
||||
* <br/>Deceleration factor (for the bounce-back effect) will be set to DEFAULT_DECELERATE_FACTOR.
|
||||
*
|
||||
* @param viewAdapter The view's encapsulation.
|
||||
*/
|
||||
public HorizontalOverScrollBounceEffectDecorator(IOverScrollDecoratorAdapter viewAdapter) {
|
||||
this(viewAdapter, DEFAULT_TOUCH_DRAG_MOVE_RATIO_FWD, DEFAULT_TOUCH_DRAG_MOVE_RATIO_BCK, DEFAULT_DECELERATE_FACTOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* C'tor, creating the effect with explicit arguments.
|
||||
* @param viewAdapter The view's encapsulation.
|
||||
* @param touchDragRatioFwd Ratio of touch distance to actual drag distance when in 'forward' direction.
|
||||
* @param touchDragRatioBck Ratio of touch distance to actual drag distance when in 'backward'
|
||||
* direction (opposite to initial one).
|
||||
* @param decelerateFactor Deceleration factor used when decelerating the motion to create the
|
||||
* bounce-back effect.
|
||||
*/
|
||||
public HorizontalOverScrollBounceEffectDecorator(IOverScrollDecoratorAdapter viewAdapter,
|
||||
float touchDragRatioFwd, float touchDragRatioBck, float decelerateFactor) {
|
||||
super(viewAdapter, decelerateFactor, touchDragRatioFwd, touchDragRatioBck);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MotionAttributes createMotionAttributes() {
|
||||
return new MotionAttributesHorizontal();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnimationAttributes createAnimationAttributes() {
|
||||
return new AnimationAttributesHorizontal();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void translateView(View view, float offset) {
|
||||
view.setTranslationX(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void translateViewAndEvent(View view, float offset, MotionEvent event) {
|
||||
view.setTranslationX(offset);
|
||||
event.offsetLocation(offset - event.getX(0), 0f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package me.everything.android.ui.overscroll;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
public interface IOverScrollDecor {
|
||||
View getView();
|
||||
|
||||
void setOverScrollStateListener(IOverScrollStateListener listener);
|
||||
void setOverScrollUpdateListener(IOverScrollUpdateListener listener);
|
||||
|
||||
/**
|
||||
* Get the current decorator's runtime state, i.e. one of the values specified by {@link IOverScrollState}.
|
||||
* @return The state.
|
||||
*/
|
||||
int getCurrentState();
|
||||
|
||||
/**
|
||||
* Detach the decorator from its associated view, thus disabling it entirely.
|
||||
*
|
||||
* <p>It is best to call this only when over-scroll isn't currently in-effect - i.e. verify that
|
||||
* <code>getCurrentState()==IOverScrollState.STATE_IDLE</code> as a precondition, or otherwise
|
||||
* use a state listener previously installed using
|
||||
* {@link #setOverScrollStateListener(IOverScrollStateListener)}.</p>
|
||||
*
|
||||
* <p>Note: Upon detachment completion, the view in question will return to the default
|
||||
* Android over-scroll configuration (i.e. {@link View.OVER_SCROLL_ALWAYS} mode). This can be
|
||||
* overridden by calling <code>View.setOverScrollMode(mode)</code> immediately thereafter.</p>
|
||||
*/
|
||||
void detach();
|
||||
}
|
||||