From 50dded2605e4d48a58aed6c012ba33c0584a5b79 Mon Sep 17 00:00:00 2001 From: shts Date: Wed, 25 Dec 2019 20:19:07 +0900 Subject: [PATCH 1/3] [wip]Update sample --- app/build.gradle | 14 +- app/src/main/AndroidManifest.xml | 8 +- .../storyprogressbar/MainActivity.java | 114 ----------- .../android/storyprogressbar/MainActivity.kt | 166 ++++++++++++++++ .../android/storyprogressbar/StoryFragment.kt | 185 ++++++++++++++++++ app/src/main/res/layout/activity_main.xml | 42 +--- app/src/main/res/layout/fragment_main.xml | 8 + app/src/main/res/layout/fragment_story.xml | 41 ++++ build.gradle | 2 + 9 files changed, 418 insertions(+), 162 deletions(-) delete mode 100644 app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.java create mode 100644 app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.kt create mode 100644 app/src/main/java/jp/shts/android/storyprogressbar/StoryFragment.kt create mode 100644 app/src/main/res/layout/fragment_main.xml create mode 100644 app/src/main/res/layout/fragment_story.xml diff --git a/app/build.gradle b/app/build.gradle index 9c6e3ab..9cfeffc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.application' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-android' android { compileSdkVersion 28 @@ -9,7 +11,6 @@ android { targetSdkVersion 28 versionCode 1 versionName "1.0" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { @@ -23,9 +24,10 @@ dependencies { implementation project(':library') implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.ext:junit:1.1.1' - androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', { - exclude group: 'com.android.support', module: 'support-annotations' - }) + implementation 'com.ToxicBakery.viewpager.transforms:view-pager-transforms:2.0.24' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.jakewharton.timber:timber:4.7.1' +} +repositories { + mavenCentral() } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9505e53..64c21af 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,16 +1,16 @@ - - + android:theme="@style/AppTheme" + tools:ignore="GoogleAppIndexingWarning"> @@ -20,4 +20,6 @@ + + \ No newline at end of file diff --git a/app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.java b/app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.java deleted file mode 100644 index 986b519..0000000 --- a/app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.java +++ /dev/null @@ -1,114 +0,0 @@ -package jp.shts.android.storyprogressbar; - -import android.os.Bundle; -import androidx.appcompat.app.AppCompatActivity; -import android.view.MotionEvent; -import android.view.View; -import android.view.WindowManager; -import android.widget.ImageView; - -import jp.shts.android.storiesprogressview.StoriesProgressView; - -public class MainActivity extends AppCompatActivity implements StoriesProgressView.StoriesListener { - - private static final int PROGRESS_COUNT = 6; - - private StoriesProgressView storiesProgressView; - private ImageView image; - - private int counter = 0; - private final int[] resources = new int[]{ - R.drawable.sample1, - R.drawable.sample2, - R.drawable.sample3, - R.drawable.sample4, - R.drawable.sample5, - R.drawable.sample6, - }; - - private final long[] durations = new long[]{ - 500L, 1000L, 1500L, 4000L, 5000L, 1000, - }; - - long pressTime = 0L; - long limit = 500L; - - private View.OnTouchListener onTouchListener = new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - pressTime = System.currentTimeMillis(); - storiesProgressView.pause(); - return false; - case MotionEvent.ACTION_UP: - long now = System.currentTimeMillis(); - storiesProgressView.resume(); - return limit < now - pressTime; - } - return false; - } - }; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); - setContentView(R.layout.activity_main); - - storiesProgressView = (StoriesProgressView) findViewById(R.id.stories); - storiesProgressView.setStoriesCount(PROGRESS_COUNT); - storiesProgressView.setStoryDuration(3000L); - // or - // storiesProgressView.setStoriesCountWithDurations(durations); - storiesProgressView.setStoriesListener(this); -// storiesProgressView.startStories(); - counter = 2; - storiesProgressView.startStories(counter); - - image = (ImageView) findViewById(R.id.image); - image.setImageResource(resources[counter]); - - // bind reverse view - View reverse = findViewById(R.id.reverse); - reverse.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - storiesProgressView.reverse(); - } - }); - reverse.setOnTouchListener(onTouchListener); - - // bind skip view - View skip = findViewById(R.id.skip); - skip.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - storiesProgressView.skip(); - } - }); - skip.setOnTouchListener(onTouchListener); - } - - @Override - public void onNext() { - image.setImageResource(resources[++counter]); - } - - @Override - public void onPrev() { - if ((counter - 1) < 0) return; - image.setImageResource(resources[--counter]); - } - - @Override - public void onComplete() { - } - - @Override - protected void onDestroy() { - // Very important ! - storiesProgressView.destroy(); - super.onDestroy(); - } -} diff --git a/app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.kt b/app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.kt new file mode 100644 index 0000000..f467d8a --- /dev/null +++ b/app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.kt @@ -0,0 +1,166 @@ +package jp.shts.android.storyprogressbar + +import android.animation.Animator +import android.animation.ValueAnimator +import android.annotation.SuppressLint +import android.os.Bundle +import android.os.Handler +import android.util.SparseIntArray +import android.view.WindowManager +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentStatePagerAdapter +import androidx.interpolator.view.animation.FastOutSlowInInterpolator +import androidx.viewpager.widget.ViewPager +import com.ToxicBakery.viewpager.transforms.CubeOutTransformer +import timber.log.Timber + +interface PageViewOperator { + fun backPageView() + fun nextPageView() +} + +class MainActivity : AppCompatActivity(), PageViewOperator { + + companion object { + private const val PAGE_COUNT = 5 + /* key: page-count, value: story-count */ + val progressState = SparseIntArray() + } + + private lateinit var viewPager: ViewPager + private lateinit var pageAdapter: PageAdapter + + private var currentPage: Int = 0 + private var pageBeforeDragging: Int = 0 + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) + setContentView(R.layout.activity_main) + + Timber.plant(Timber.DebugTree()) + + pageAdapter = PageAdapter(supportFragmentManager) + viewPager = findViewById(R.id.viewpager) + viewPager.adapter = pageAdapter + viewPager.setPageTransformer(true, CubeOutTransformer()) + viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrollStateChanged(state: Int) { + when (state) { + 0 -> { + Timber.v("onPageScrollStateChanged(SCROLL_STATE_IDLE)") + Handler().postDelayed({ + if (pageBeforeDragging == currentPage) { + currentFragment()?.resume() + } + }, 500) + } + 1 -> { + pageBeforeDragging = currentPage + Timber.v("onPageScrollStateChanged(SCROLL_STATE_DRAGGING)") + } + 2 -> { + Timber.v("onPageScrollStateChanged(SCROLL_STATE_SETTLING)") + } + } + + // SCROLL_STATE_SETTLING してから onPageSelected が 500ml 以内に呼ばれなければ resume する。 +// currentFragment()?.resume() + } + + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + } + + override fun onPageSelected(position: Int) { + Timber.v("onPageSelected(${position})") + currentPage = position + currentFragment()?.resume() + } + }) + } + + private fun currentFragment(): StoryFragment? { + return pageAdapter.findFragmentByPosition(viewPager, currentPage) as StoryFragment + } + + override fun backPageView() { + if (viewPager.currentItem > 0) { + fakeDrag(false) + } + } + + override fun nextPageView() { + if (viewPager.currentItem + 1 < viewPager.adapter?.count ?: 0) { + fakeDrag(true) + } + } + + private var prevDragPosition = 0 + + /** + * Change ViewPage sliding programmatically(not using reflection). + * https://tech.dely.jp/entry/2018/12/13/110000 + * What for? + * setCurrentItem(int, boolean) changes too fast. And it cannot set animation duration. + */ + private fun fakeDrag(forward: Boolean) { + if (prevDragPosition == 0 && viewPager.beginFakeDrag()) { + ValueAnimator.ofInt(0, viewPager.width).apply { + duration = 500L + interpolator = FastOutSlowInInterpolator() + addListener(object : Animator.AnimatorListener { + + override fun onAnimationStart(animation: Animator?) = Unit + + override fun onAnimationEnd(animation: Animator?) { + removeAllUpdateListeners() + if (viewPager.isFakeDragging) { + viewPager.endFakeDrag() + } + prevDragPosition = 0 + } + + override fun onAnimationCancel(animation: Animator?) { + removeAllUpdateListeners() + if (viewPager.isFakeDragging) { + viewPager.endFakeDrag() + } + prevDragPosition = 0 + } + + override fun onAnimationRepeat(animation: Animator?) = Unit + }) + addUpdateListener { + if (!viewPager.isFakeDragging) { + return@addUpdateListener + } + val dragPosition: Int = it.animatedValue as Int + val dragOffset: Float = ((dragPosition - prevDragPosition) * if (forward) -1 else 1).toFloat() + prevDragPosition = dragPosition + viewPager.fakeDragBy(dragOffset) + } + }.start() + } + } + + private class PageAdapter internal constructor(fragmentManager: FragmentManager) : + FragmentStatePagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { + override fun getItem(position: Int): Fragment = StoryFragment.createIntent(position) + override fun getCount(): Int { + return PAGE_COUNT + } + /** + * https://qiita.com/chooblarin/items/88b4accac0cbb6944d4b#%E6%96%B9%E6%B3%953-instantiateitem%E3%82%92%E4%BD%BF%E3%81%86 + */ + fun findFragmentByPosition(viewPager: ViewPager, position: Int): Fragment? { + try { + val f = instantiateItem(viewPager, position) + return f as? Fragment + } finally { + finishUpdate(viewPager) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/jp/shts/android/storyprogressbar/StoryFragment.kt b/app/src/main/java/jp/shts/android/storyprogressbar/StoryFragment.kt new file mode 100644 index 0000000..2f992e1 --- /dev/null +++ b/app/src/main/java/jp/shts/android/storyprogressbar/StoryFragment.kt @@ -0,0 +1,185 @@ +package jp.shts.android.storyprogressbar + +import android.content.Context +import android.os.Bundle +import android.view.* +import androidx.fragment.app.Fragment + +import android.widget.ImageView + +import jp.shts.android.storiesprogressview.StoriesProgressView +import timber.log.Timber + +class StoryFragment : Fragment(), StoriesProgressView.StoriesListener { + + companion object { + private const val PROGRESS_COUNT = 6 + private const val EXTRA_POSITION = "extra_position" + + fun createIntent(position: Int): StoryFragment { + return StoryFragment().apply { + arguments = Bundle().apply { + putInt(EXTRA_POSITION, position) + } + } + } + } + + private var storiesProgressView: StoriesProgressView? = null + private var image: ImageView? = null + + private var counter = 0 + private val resources = intArrayOf( + R.drawable.sample1, + R.drawable.sample2, + R.drawable.sample3, + R.drawable.sample4, + R.drawable.sample5, + R.drawable.sample6 + ) + + private val durations = longArrayOf(500L, 1000L, 1500L, 4000L, 5000L, 1000) + + private var pressTime = 0L + private var limit = 500L + + private val onTouchListener = View.OnTouchListener { _, event -> + when (event.action) { + MotionEvent.ACTION_DOWN -> { + pressTime = System.currentTimeMillis() + Timber.v("MotionEvent.ACTION_DOWN") + storiesProgressView?.pause() + return@OnTouchListener false + } + MotionEvent.ACTION_UP -> { + Timber.v("MotionEvent.ACTION_UP") + val now = System.currentTimeMillis() + storiesProgressView?.resume() + return@OnTouchListener limit < now - pressTime + } + } + false + } + + private var pageViewOperator: PageViewOperator? = null + + override fun onAttach(context: Context) { + super.onAttach(context) + if (context is PageViewOperator) { + this.pageViewOperator = context + } + } + + override fun onStart() { + super.onStart() + Timber.v("${arguments?.getInt(EXTRA_POSITION)}: onStart") + counter = restorePosition() + } + + override fun onStop() { + super.onStop() + Timber.v("${arguments?.getInt(EXTRA_POSITION)}: onStop") + } + + override fun onResume() { + super.onResume() + Timber.d("${arguments?.getInt(EXTRA_POSITION)}: onResume") + if (counter == 0) { + // start animation + storiesProgressView?.startStories() + } else { + // restart animation + counter = MainActivity.progressState.get(arguments?.getInt(EXTRA_POSITION) ?: 0) + storiesProgressView?.startStories(counter) + } + } + + override fun onPause() { + super.onPause() + Timber.v("${arguments?.getInt(EXTRA_POSITION)}: onPause") + pause() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val view = inflater.inflate(R.layout.fragment_story, container, false) + storiesProgressView = view.findViewById(R.id.stories) + storiesProgressView?.setStoriesCount(PROGRESS_COUNT) + storiesProgressView?.setStoryDuration(3000L) + // or + // storiesProgressView.setStoriesCountWithDurations(durations); + storiesProgressView?.setStoriesListener(this) + + // bind image + image = view.findViewById(R.id.image) + image?.setImageResource(resources[counter]) + + // bind reverse view + val reverse = view.findViewById(R.id.reverse) + reverse.setOnClickListener { + if (counter == 0) { + pageViewOperator?.backPageView() + } else { + storiesProgressView?.reverse() + } + } + reverse.setOnTouchListener(onTouchListener) + + // bind skip view + val skip = view.findViewById(R.id.skip) + skip.setOnClickListener { + if (counter == resources.size) { + pageViewOperator?.nextPageView() + } else { + storiesProgressView?.skip() + } + } + skip.setOnTouchListener(onTouchListener) + return view + } + + fun pause() { + storiesProgressView?.pause() + } + + fun resume() { + storiesProgressView?.resume() + } + + override fun onDestroyView() { + Timber.w("${arguments?.getInt(EXTRA_POSITION)}: onDestroyView") + savePosition(counter) + // Very important ! + storiesProgressView?.destroy() + super.onDestroyView() + } + + private fun savePosition(position: Int) { + MainActivity.progressState.put(arguments!!.getInt(EXTRA_POSITION), position) + } + + private fun restorePosition(): Int { + return MainActivity.progressState.get(arguments!!.getInt(EXTRA_POSITION)) + } + + /* implement StoriesProgressView.StoriesListener start */ + override fun onNext() { + if (resources.size < counter + 1) { + return + } + savePosition(counter + 1) + image?.setImageResource(resources[++counter]) + } + + override fun onPrev() { + if (counter - 1 < 0) { + return + } + savePosition(counter - 1) + image?.setImageResource(resources[--counter]) + } + + override fun onComplete() { + pageViewOperator?.nextPageView() + } + /* implement StoriesProgressView.StoriesListener end */ +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 6568439..a65147a 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,41 +1,5 @@ - - - - - - - - - - - - - \ No newline at end of file + android:layout_height="match_parent" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml new file mode 100644 index 0000000..2608743 --- /dev/null +++ b/app/src/main/res/layout/fragment_main.xml @@ -0,0 +1,8 @@ + + diff --git a/app/src/main/res/layout/fragment_story.xml b/app/src/main/res/layout/fragment_story.xml new file mode 100644 index 0000000..34bb0aa --- /dev/null +++ b/app/src/main/res/layout/fragment_story.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 68e19b3..3f35f09 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext.kotlin_version = '1.3.61' repositories { jcenter() mavenCentral() @@ -9,6 +10,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.5.1' classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } From f322eccc87a344df9598aad8b33555b31a9472ad Mon Sep 17 00:00:00 2001 From: shts Date: Thu, 26 Dec 2019 22:57:34 +0900 Subject: [PATCH 2/3] wip --- .../android/storyprogressbar/MainActivity.kt | 38 +++---------- .../storyprogressbar/PageChangeListener.kt | 54 +++++++++++++++++++ .../android/storyprogressbar/StoryFragment.kt | 26 ++++----- .../PausableProgressBar.java | 16 ++++++ .../StoriesProgressView.java | 8 +++ 5 files changed, 98 insertions(+), 44 deletions(-) create mode 100644 app/src/main/java/jp/shts/android/storyprogressbar/PageChangeListener.kt diff --git a/app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.kt b/app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.kt index f467d8a..7c95a94 100644 --- a/app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.kt +++ b/app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.kt @@ -2,9 +2,7 @@ package jp.shts.android.storyprogressbar import android.animation.Animator import android.animation.ValueAnimator -import android.annotation.SuppressLint import android.os.Bundle -import android.os.Handler import android.util.SparseIntArray import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity @@ -25,7 +23,7 @@ class MainActivity : AppCompatActivity(), PageViewOperator { companion object { private const val PAGE_COUNT = 5 - /* key: page-count, value: story-count */ + /* key: page-count, value: story-count */ val progressState = SparseIntArray() } @@ -33,7 +31,6 @@ class MainActivity : AppCompatActivity(), PageViewOperator { private lateinit var pageAdapter: PageAdapter private var currentPage: Int = 0 - private var pageBeforeDragging: Int = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -46,37 +43,14 @@ class MainActivity : AppCompatActivity(), PageViewOperator { viewPager = findViewById(R.id.viewpager) viewPager.adapter = pageAdapter viewPager.setPageTransformer(true, CubeOutTransformer()) - viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { - override fun onPageScrollStateChanged(state: Int) { - when (state) { - 0 -> { - Timber.v("onPageScrollStateChanged(SCROLL_STATE_IDLE)") - Handler().postDelayed({ - if (pageBeforeDragging == currentPage) { - currentFragment()?.resume() - } - }, 500) - } - 1 -> { - pageBeforeDragging = currentPage - Timber.v("onPageScrollStateChanged(SCROLL_STATE_DRAGGING)") - } - 2 -> { - Timber.v("onPageScrollStateChanged(SCROLL_STATE_SETTLING)") - } - } - - // SCROLL_STATE_SETTLING してから onPageSelected が 500ml 以内に呼ばれなければ resume する。 -// currentFragment()?.resume() - } - - override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + viewPager.addOnPageChangeListener(object : PageChangeListener() { + override fun onPageScrollCanceled() { + currentFragment()?.resume() } - override fun onPageSelected(position: Int) { - Timber.v("onPageSelected(${position})") + super.onPageSelected(position) currentPage = position - currentFragment()?.resume() +// currentFragment()?.resume() } }) } diff --git a/app/src/main/java/jp/shts/android/storyprogressbar/PageChangeListener.kt b/app/src/main/java/jp/shts/android/storyprogressbar/PageChangeListener.kt new file mode 100644 index 0000000..2810c8a --- /dev/null +++ b/app/src/main/java/jp/shts/android/storyprogressbar/PageChangeListener.kt @@ -0,0 +1,54 @@ +package jp.shts.android.storyprogressbar + +import android.os.Handler +import android.os.HandlerThread +import android.os.Message +import androidx.viewpager.widget.ViewPager.* +import timber.log.Timber + +abstract class PageChangeListener : OnPageChangeListener { + + companion object { + private const val DEBOUNCE_TIMES = 500L + } + + private var pageBeforeDragging = 0 + private var currentPage = 0 + private var lastTime = DEBOUNCE_TIMES + 1L + + override fun onPageScrollStateChanged(state: Int) { + when (state) { + SCROLL_STATE_IDLE -> { + Timber.d("onPageScrollStateChanged(): SCROLL_STATE_IDLE") + // 500ms 以下間隔のリクエストは破棄する + val now = System.currentTimeMillis() + if (now - lastTime < DEBOUNCE_TIMES) { + return + } + lastTime = now + Handler().postDelayed({ + if (pageBeforeDragging == currentPage) { + onPageScrollCanceled() + } + }, 300L) + } + SCROLL_STATE_DRAGGING -> { + Timber.d("onPageScrollStateChanged(): SCROLL_STATE_DRAGGING") + pageBeforeDragging = currentPage + } + SCROLL_STATE_SETTLING -> { + Timber.d("onPageScrollStateChanged(): SCROLL_STATE_SETTLING") + } + } + } + + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + } + + override fun onPageSelected(position: Int) { + Timber.d("onPageSelected(): position($position)") + currentPage = position + } + + abstract fun onPageScrollCanceled() +} diff --git a/app/src/main/java/jp/shts/android/storyprogressbar/StoryFragment.kt b/app/src/main/java/jp/shts/android/storyprogressbar/StoryFragment.kt index 2f992e1..e16a4fc 100644 --- a/app/src/main/java/jp/shts/android/storyprogressbar/StoryFragment.kt +++ b/app/src/main/java/jp/shts/android/storyprogressbar/StoryFragment.kt @@ -47,12 +47,10 @@ class StoryFragment : Fragment(), StoriesProgressView.StoriesListener { when (event.action) { MotionEvent.ACTION_DOWN -> { pressTime = System.currentTimeMillis() - Timber.v("MotionEvent.ACTION_DOWN") storiesProgressView?.pause() return@OnTouchListener false } MotionEvent.ACTION_UP -> { - Timber.v("MotionEvent.ACTION_UP") val now = System.currentTimeMillis() storiesProgressView?.resume() return@OnTouchListener limit < now - pressTime @@ -90,6 +88,7 @@ class StoryFragment : Fragment(), StoriesProgressView.StoriesListener { } else { // restart animation counter = MainActivity.progressState.get(arguments?.getInt(EXTRA_POSITION) ?: 0) + Timber.d("startStories onResume(): currentPage(${arguments?.getInt(EXTRA_POSITION)}) counter($counter)") storiesProgressView?.startStories(counter) } } @@ -97,20 +96,24 @@ class StoryFragment : Fragment(), StoriesProgressView.StoriesListener { override fun onPause() { super.onPause() Timber.v("${arguments?.getInt(EXTRA_POSITION)}: onPause") - pause() +// storiesProgressView?.pause() + storiesProgressView?.abandon() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + counter = restorePosition() } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_story, container, false) - storiesProgressView = view.findViewById(R.id.stories) + storiesProgressView = view.findViewById(R.id.stories) storiesProgressView?.setStoriesCount(PROGRESS_COUNT) storiesProgressView?.setStoryDuration(3000L) - // or - // storiesProgressView.setStoriesCountWithDurations(durations); storiesProgressView?.setStoriesListener(this) // bind image - image = view.findViewById(R.id.image) + image = view.findViewById(R.id.image) image?.setImageResource(resources[counter]) // bind reverse view @@ -127,7 +130,8 @@ class StoryFragment : Fragment(), StoriesProgressView.StoriesListener { // bind skip view val skip = view.findViewById(R.id.skip) skip.setOnClickListener { - if (counter == resources.size) { + Timber.d("counter($counter) resources.size(${resources.size})") + if (counter == resources.size - 1) { pageViewOperator?.nextPageView() } else { storiesProgressView?.skip() @@ -137,11 +141,8 @@ class StoryFragment : Fragment(), StoriesProgressView.StoriesListener { return view } - fun pause() { - storiesProgressView?.pause() - } - fun resume() { + Timber.d("${arguments?.getInt(EXTRA_POSITION)}: resume") storiesProgressView?.resume() } @@ -163,6 +164,7 @@ class StoryFragment : Fragment(), StoriesProgressView.StoriesListener { /* implement StoriesProgressView.StoriesListener start */ override fun onNext() { + Timber.d("onNext(): counter($counter)") if (resources.size < counter + 1) { return } diff --git a/library/src/main/java/jp/shts/android/storiesprogressview/PausableProgressBar.java b/library/src/main/java/jp/shts/android/storiesprogressview/PausableProgressBar.java index af7e472..f131dfc 100644 --- a/library/src/main/java/jp/shts/android/storiesprogressview/PausableProgressBar.java +++ b/library/src/main/java/jp/shts/android/storiesprogressview/PausableProgressBar.java @@ -5,6 +5,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import android.util.AttributeSet; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.animation.Animation; @@ -13,8 +14,12 @@ import android.view.animation.Transformation; import android.widget.FrameLayout; +import java.util.UUID; + final class PausableProgressBar extends FrameLayout { + private static final String TAG = StoriesProgressView.class.getSimpleName(); + /*** * progress満了タイマーのデフォルト時間 */ @@ -26,6 +31,7 @@ final class PausableProgressBar extends FrameLayout { private PausableScaleAnimation animation; private long duration = DEFAULT_PROGRESS_DURATION; private Callback callback; + private String uuid = UUID.randomUUID().toString(); interface Callback { void onStartProgress(); @@ -95,7 +101,10 @@ private void finishProgress(boolean isMax) { } } + private boolean isStarted = false; + public void startProgress() { + Log.v(TAG, uuid + ": startProgress"); maxProgressView.setVisibility(GONE); animation = new PausableScaleAnimation(0, 1, 1, 1, Animation.ABSOLUTE, 0, Animation.RELATIVE_TO_SELF, 0); @@ -104,6 +113,11 @@ public void startProgress() { animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { + if (isStarted) { + return; + } + isStarted = true; + Log.d(TAG, uuid + ": onAnimationStart"); frontProgressView.setVisibility(View.VISIBLE); if (callback != null) callback.onStartProgress(); } @@ -114,6 +128,8 @@ public void onAnimationRepeat(Animation animation) { @Override public void onAnimationEnd(Animation animation) { + isStarted = false; + Log.d(TAG, uuid + ": onAnimationEnd"); if (callback != null) callback.onFinishProgress(); } }); diff --git a/library/src/main/java/jp/shts/android/storiesprogressview/StoriesProgressView.java b/library/src/main/java/jp/shts/android/storiesprogressview/StoriesProgressView.java index ec8c22e..5f86a59 100644 --- a/library/src/main/java/jp/shts/android/storiesprogressview/StoriesProgressView.java +++ b/library/src/main/java/jp/shts/android/storiesprogressview/StoriesProgressView.java @@ -7,11 +7,13 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import android.util.AttributeSet; +import android.util.Log; import android.view.View; import android.widget.LinearLayout; import java.util.ArrayList; import java.util.List; +import java.util.Timer; public class StoriesProgressView extends LinearLayout { @@ -209,7 +211,9 @@ public void startStories() { * Start progress animation from specific progress */ public void startStories(int from) { + Log.w(TAG, "startStories start from(" + from + ")"); for (int i = 0; i < from; i++) { + progressBars.get(i).clear(); progressBars.get(i).setMaxWithoutCallback(); } progressBars.get(from).startProgress(); @@ -224,6 +228,10 @@ public void destroy() { } } + public void abandon() { + progressBars.get(current).setMinWithoutCallback(); + } + /** * Pause story */ From 3070a00c26bad05cbe6f3eed25cecc71698e196a Mon Sep 17 00:00:00 2001 From: shts Date: Fri, 27 Dec 2019 19:12:16 +0900 Subject: [PATCH 3/3] wip --- .../shts/android/storyprogressbar/MainActivity.kt | 1 + .../shts/android/storyprogressbar/StoryFragment.kt | 7 +++++-- app/src/main/res/layout/fragment_story.xml | 5 +++++ .../storiesprogressview/PausableProgressBar.java | 7 +++---- .../storiesprogressview/StoriesProgressView.java | 13 +++++++++++-- 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.kt b/app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.kt index 7c95a94..ffc8cb8 100644 --- a/app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.kt +++ b/app/src/main/java/jp/shts/android/storyprogressbar/MainActivity.kt @@ -45,6 +45,7 @@ class MainActivity : AppCompatActivity(), PageViewOperator { viewPager.setPageTransformer(true, CubeOutTransformer()) viewPager.addOnPageChangeListener(object : PageChangeListener() { override fun onPageScrollCanceled() { + Timber.d("onPageScrollCanceled()") currentFragment()?.resume() } override fun onPageSelected(position: Int) { diff --git a/app/src/main/java/jp/shts/android/storyprogressbar/StoryFragment.kt b/app/src/main/java/jp/shts/android/storyprogressbar/StoryFragment.kt index e16a4fc..0b39eab 100644 --- a/app/src/main/java/jp/shts/android/storyprogressbar/StoryFragment.kt +++ b/app/src/main/java/jp/shts/android/storyprogressbar/StoryFragment.kt @@ -1,5 +1,6 @@ package jp.shts.android.storyprogressbar +import android.annotation.SuppressLint import android.content.Context import android.os.Bundle import android.view.* @@ -88,7 +89,7 @@ class StoryFragment : Fragment(), StoriesProgressView.StoriesListener { } else { // restart animation counter = MainActivity.progressState.get(arguments?.getInt(EXTRA_POSITION) ?: 0) - Timber.d("startStories onResume(): currentPage(${arguments?.getInt(EXTRA_POSITION)}) counter($counter)") + Timber.d("startStories via onResume(): cp(${arguments?.getInt(EXTRA_POSITION)}) c($counter)") storiesProgressView?.startStories(counter) } } @@ -108,13 +109,14 @@ class StoryFragment : Fragment(), StoriesProgressView.StoriesListener { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_story, container, false) storiesProgressView = view.findViewById(R.id.stories) - storiesProgressView?.setStoriesCount(PROGRESS_COUNT) + storiesProgressView?.setStoriesCountDebug(PROGRESS_COUNT, arguments?.getInt(EXTRA_POSITION) ?: -1) storiesProgressView?.setStoryDuration(3000L) storiesProgressView?.setStoriesListener(this) // bind image image = view.findViewById(R.id.image) image?.setImageResource(resources[counter]) + image?.setOnTouchListener(onTouchListener) // bind reverse view val reverse = view.findViewById(R.id.reverse) @@ -142,6 +144,7 @@ class StoryFragment : Fragment(), StoriesProgressView.StoriesListener { } fun resume() { + Timber.d("startStories via onPageScrollCanceled(): cp(${arguments?.getInt(EXTRA_POSITION)}) c($counter)") Timber.d("${arguments?.getInt(EXTRA_POSITION)}: resume") storiesProgressView?.resume() } diff --git a/app/src/main/res/layout/fragment_story.xml b/app/src/main/res/layout/fragment_story.xml index 34bb0aa..3307bfc 100644 --- a/app/src/main/res/layout/fragment_story.xml +++ b/app/src/main/res/layout/fragment_story.xml @@ -23,6 +23,11 @@ android:layout_height="match_parent" android:layout_weight="1" /> + +