diff --git a/app/build.gradle b/app/build.gradle index 96e6f759..f14ad6d6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -84,9 +84,6 @@ dependencies { //Local Files implementation fileTree(include: ["*.jar"], dir: "libs") - //滑动返回 - implementation "me.imid.swipebacklayout.lib:library:1.3.0" - //兼容 Glide implementation "com.android.support:support-annotations:28.0.0" kapt "com.android.support:support-annotations:28.0.0" diff --git a/app/src/main/java/com/huanchengfly/tieba/post/activities/BaseActivity.kt b/app/src/main/java/com/huanchengfly/tieba/post/activities/BaseActivity.kt index a28c2066..7f4e24bf 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/activities/BaseActivity.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/activities/BaseActivity.kt @@ -23,6 +23,7 @@ import androidx.annotation.CallSuper import androidx.annotation.ColorInt import androidx.annotation.Keep import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import butterknife.ButterKnife import cn.jzvd.Jzvd @@ -30,16 +31,16 @@ import com.gyf.immersionbar.ImmersionBar import com.huanchengfly.tieba.post.BaseApplication import com.huanchengfly.tieba.post.BaseApplication.Companion.instance import com.huanchengfly.tieba.post.R +import com.huanchengfly.tieba.post.ui.slideback.SlideBack import com.huanchengfly.tieba.post.ui.theme.interfaces.ExtraRefreshable import com.huanchengfly.tieba.post.ui.theme.utils.ThemeUtils import com.huanchengfly.tieba.post.utils.* import com.huanchengfly.tieba.post.widgets.VoicePlayerView import com.huanchengfly.tieba.post.widgets.theme.TintToolbar import kotlinx.coroutines.* -import me.imid.swipebacklayout.lib.app.SwipeBackActivity import kotlin.coroutines.CoroutineContext -abstract class BaseActivity : SwipeBackActivity(), ExtraRefreshable, CoroutineScope { +abstract class BaseActivity : AppCompatActivity(), ExtraRefreshable, CoroutineScope { val job = Job() override val coroutineContext: CoroutineContext get() = Dispatchers.Main + job @@ -99,6 +100,8 @@ abstract class BaseActivity : SwipeBackActivity(), ExtraRefreshable, CoroutineSc override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + SlideBack.create() + .attachToActivity(this) fixBackground() getDeviceDensity() instance.addActivity(this) diff --git a/app/src/main/java/com/huanchengfly/tieba/post/activities/MainActivity.kt b/app/src/main/java/com/huanchengfly/tieba/post/activities/MainActivity.kt index 71cb3341..745daed2 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/activities/MainActivity.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/activities/MainActivity.kt @@ -166,7 +166,6 @@ open class MainActivity : BaseActivity(), NavigationBarView.OnItemSelectedListen override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setSwipeBackEnable(false) ThemeUtil.setTranslucentThemeBackground(findViewById(R.id.background)) findView() initView() diff --git a/app/src/main/java/com/huanchengfly/tieba/post/activities/NewSearchActivity.kt b/app/src/main/java/com/huanchengfly/tieba/post/activities/NewSearchActivity.kt index f9893c13..af63fa8b 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/activities/NewSearchActivity.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/activities/NewSearchActivity.kt @@ -10,14 +10,11 @@ import android.view.inputmethod.EditorInfo import android.widget.EditText import android.widget.ImageView import android.widget.LinearLayout -import android.widget.TextView -import androidx.core.widget.TextViewCompat import androidx.recyclerview.widget.RecyclerView import butterknife.BindView import cn.dreamtobe.kpswitch.util.KeyboardUtil import com.alibaba.android.vlayout.DelegateAdapter import com.alibaba.android.vlayout.VirtualLayoutManager -import com.alibaba.android.vlayout.layout.LinearLayoutHelper import com.google.android.material.tabs.TabLayout import com.google.android.material.textfield.TextInputLayout import com.huanchengfly.tieba.post.R @@ -26,8 +23,6 @@ import com.huanchengfly.tieba.post.adapters.HeaderDelegateAdapter import com.huanchengfly.tieba.post.adapters.HeaderDelegateAdapter.Companion.NO_ICON import com.huanchengfly.tieba.post.adapters.SearchHistoryAdapter import com.huanchengfly.tieba.post.adapters.SingleLayoutDelegateAdapter -import com.huanchengfly.tieba.post.adapters.base.BaseSingleTypeDelegateAdapter -import com.huanchengfly.tieba.post.api.models.web.HotMessageListBean import com.huanchengfly.tieba.post.components.AutoLineFeedLayoutManager import com.huanchengfly.tieba.post.components.MyViewHolder import com.huanchengfly.tieba.post.components.dividers.SpacesItemDecoration @@ -35,16 +30,13 @@ import com.huanchengfly.tieba.post.dpToPx import com.huanchengfly.tieba.post.fragments.SearchForumFragment import com.huanchengfly.tieba.post.fragments.SearchThreadFragment import com.huanchengfly.tieba.post.fragments.SearchUserFragment -import com.huanchengfly.tieba.post.getColorCompat import com.huanchengfly.tieba.post.interfaces.ISearchFragment import com.huanchengfly.tieba.post.models.database.SearchHistory import com.huanchengfly.tieba.post.toastShort import com.huanchengfly.tieba.post.ui.theme.utils.ColorStateListUtils import com.huanchengfly.tieba.post.utils.AnimUtil -import com.huanchengfly.tieba.post.utils.NavigationHelper import com.huanchengfly.tieba.post.utils.ThemeUtil import com.huanchengfly.tieba.post.utils.anim.animSet -import com.huanchengfly.tieba.post.utils.getIntermixedColorBackground import com.huanchengfly.tieba.post.widgets.MyViewPager import org.litepal.LitePal @@ -69,8 +61,6 @@ class NewSearchActivity : BaseActivity(), TabLayout.OnTabSelectedListener { @BindView(R.id.bottom_app_bar) lateinit var bottomAppBar: View - var hotMessageListBean: HotMessageListBean? = null - private var keyword: String? = null set(value) { field = value @@ -260,51 +250,6 @@ class NewSearchActivity : BaseActivity(), TabLayout.OnTabSelectedListener { } } - inner class HotTopicDelegateAdapter( - list: List? = null - ) : BaseSingleTypeDelegateAdapter( - this, - LinearLayoutHelper(), - list - ) { - override fun convert(viewHolder: MyViewHolder, item: HotMessageListBean.HotMessageRetBean, position: Int) { - viewHolder.setText(R.id.hot_order, "${position + 1}") - viewHolder.setText(R.id.hot_title, item.mulName) - viewHolder.setText(R.id.hot_desc, item.topicInfo.topicDesc) - val textView = viewHolder.getView(R.id.hot_order) - if (position > 2) { - TextViewCompat.setTextAppearance(textView, R.style.TextAppearance_Bold) - textView.setTextColor(context.getColorCompat(R.color.tieba)) - } else { - TextViewCompat.setTextAppearance(textView, R.style.TextAppearance_Bold_Italic) - textView.setTextColor(context.getColorCompat(R.color.red_accent)) - } - viewHolder.setVisibility(R.id.hot_desc, View.GONE) - viewHolder.itemView.background = getIntermixedColorBackground( - context, - position, - itemCount, - positionOffset = 1, - colors = intArrayOf(R.color.default_color_card, R.color.default_color_divider), - radius = context.resources.getDimension(R.dimen.card_radius) - ) - } - - override fun getItemLayoutId(): Int { - return R.layout.item_hot_message_list - } - - init { - val navigationHelper = NavigationHelper.newInstance(context) - setOnItemClickListener { _, item, _ -> - navigationHelper.navigationByData( - NavigationHelper.ACTION_URL, - "https://tieba.baidu.com/mo/q/hotMessage?topic_id=${item.mulId}&topic_name=${item.mulName}" - ) - } - } - } - override fun onTabSelected(tab: TabLayout.Tab) { val fragment = fragmentAdapter.fragments[tab.position] if (fragment is Filterable) { diff --git a/app/src/main/java/com/huanchengfly/tieba/post/activities/OKSignActivity.java b/app/src/main/java/com/huanchengfly/tieba/post/activities/OKSignActivity.java index 0207c9fe..6762bccc 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/activities/OKSignActivity.java +++ b/app/src/main/java/com/huanchengfly/tieba/post/activities/OKSignActivity.java @@ -2,12 +2,11 @@ package com.huanchengfly.tieba.post.activities; import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; + import com.huanchengfly.tieba.post.utils.TiebaUtil; -import me.imid.swipebacklayout.lib.app.SwipeBackActivity; - -public class OKSignActivity extends SwipeBackActivity { - +public class OKSignActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/app/src/main/java/com/huanchengfly/tieba/post/activities/ReplyActivity.kt b/app/src/main/java/com/huanchengfly/tieba/post/activities/ReplyActivity.kt index ecdf74e9..bd34d1c4 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/activities/ReplyActivity.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/activities/ReplyActivity.kt @@ -113,9 +113,8 @@ class ReplyActivity : BaseActivity(), View.OnClickListener, override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setSwipeBackEnable(false) if (ThemeUtil.THEME_TRANSLUCENT == ThemeUtil.getTheme(this)) { - val constraintLayout = findViewById(R.id.activity_reply_layout) as TintConstraintLayout + val constraintLayout = findViewById(R.id.activity_reply_layout) constraintLayout.setBackgroundTintResId(0) ThemeUtil.setTranslucentBackground(constraintLayout) } @@ -278,8 +277,8 @@ class ReplyActivity : BaseActivity(), View.OnClickListener, } }) mItemTouchHelper.attachToRecyclerView(insertView) - findViewById(R.id.activity_reply_root).setOnClickListener(this) - findViewById(R.id.activity_reply_layout).setOnClickListener(this) + findViewById(R.id.activity_reply_root).setOnClickListener(this) + findViewById(R.id.activity_reply_layout).setOnClickListener(this) toolbar.setNavigationIcon(R.drawable.ic_reply_toolbar_round_close) if (replyInfoBean!!.pid == null && replyInfoBean!!.floorNum == null) { insertImageBtn.visibility = View.VISIBLE @@ -293,7 +292,7 @@ class ReplyActivity : BaseActivity(), View.OnClickListener, if (replyInfoBean!!.replyUser != null) { editText.hint = getString(R.string.hint_reply, replyInfoBean!!.replyUser) } - val tabLayout = findViewById(R.id.activity_reply_emotion_tab) as TabLayout + val tabLayout = findViewById(R.id.activity_reply_emotion_tab) val emotionViewPagerAdapter = TabViewPagerAdapter() val classicEmotionGridView = GridView(this) val emojiEmotionGridView = GridView(this) @@ -430,9 +429,9 @@ class ReplyActivity : BaseActivity(), View.OnClickListener, } private fun initListener() { - val undo = findViewById(R.id.activity_reply_edit_undo) as TintImageView - val redo = findViewById(R.id.activity_reply_edit_redo) as TintImageView - val clear = findViewById(R.id.activity_reply_edit_clear) as TintImageView + val undo = findViewById(R.id.activity_reply_edit_undo) + val redo = findViewById(R.id.activity_reply_edit_redo) + val clear = findViewById(R.id.activity_reply_edit_clear) undo.setOnClickListener(this) setEnabled(undo, false) redo.setOnClickListener(this) diff --git a/app/src/main/java/com/huanchengfly/tieba/post/activities/ThreadActivity.kt b/app/src/main/java/com/huanchengfly/tieba/post/activities/ThreadActivity.kt index 59f03e59..becb5f78 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/activities/ThreadActivity.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/activities/ThreadActivity.kt @@ -52,7 +52,6 @@ import com.huanchengfly.tieba.post.utils.preload.PreloadUtil import com.huanchengfly.tieba.post.utils.preload.loaders.ThreadContentLoader import com.huanchengfly.tieba.post.widgets.VideoPlayerStandard import com.scwang.smart.refresh.layout.SmartRefreshLayout -import me.imid.swipebacklayout.lib.SwipeBackLayout.SwipeListener import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -174,13 +173,6 @@ class ThreadActivity : BaseActivity(), View.OnClickListener, IThreadMenuFragment override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ThemeUtil.setTranslucentThemeBackground(findViewById(R.id.background)) - swipeBackLayout.addSwipeListener(object : SwipeListener { - override fun onScrollStateChange(state: Int, scrollPercent: Float) {} - override fun onScrollOverThreshold() {} - override fun onEdgeTouch(edgeFlag: Int) { - exit() - } - }) refreshLayout.apply { ThemeUtil.setThemeForSmartRefreshLayout(this) refreshLayout.setOnRefreshListener { @@ -243,8 +235,8 @@ class ThreadActivity : BaseActivity(), View.OnClickListener, IThreadMenuFragment setSupportActionBar(toolbar) supportActionBar?.title = null supportActionBar?.setDisplayHomeAsUpEnabled(true) - findViewById(R.id.thread_bottom_bar_agree).setOnClickListener(this) - findViewById(R.id.thread_reply_bar).setOnClickListener(this) + findViewById(R.id.thread_bottom_bar_agree).setOnClickListener(this) + findViewById(R.id.thread_reply_bar).setOnClickListener(this) moreBtn.setOnClickListener(this) toolbar.setOnClickListener(this) threadHeaderAdapter.setOnToggleSeeLzListener { diff --git a/app/src/main/java/com/huanchengfly/tieba/post/activities/TranslucentThemeActivity.kt b/app/src/main/java/com/huanchengfly/tieba/post/activities/TranslucentThemeActivity.kt index 9d9be18f..19c8e4f1 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/activities/TranslucentThemeActivity.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/activities/TranslucentThemeActivity.kt @@ -204,7 +204,7 @@ class TranslucentThemeActivity : BaseActivity(), View.OnClickListener, OnSeekBar private fun refreshBackground() { mProgress.visibility = View.VISIBLE if (mUri == null) { - findViewById(R.id.background).setBackgroundColor(Color.BLACK) + findViewById(R.id.background).setBackgroundColor(Color.BLACK) mProgress.visibility = View.GONE return } @@ -222,7 +222,8 @@ class TranslucentThemeActivity : BaseActivity(), View.OnClickListener, OnSeekBar override fun onResourceReady(resource: Drawable, transition: Transition?) { resource.alpha = alpha val bitmap = ImageUtil.drawableToBitmap(resource) - findViewById(R.id.background).background = BitmapDrawable(resources, bitmap) + findViewById(R.id.background).background = + BitmapDrawable(resources, bitmap) mPalette = Palette.from(bitmap).generate() mTranslucentThemeColorAdapter.setPalette(mPalette) mSelectColor.visibility = View.VISIBLE @@ -291,7 +292,7 @@ class TranslucentThemeActivity : BaseActivity(), View.OnClickListener, OnSeekBar appPreferences.translucentPrimaryColor = toString(themeColor) ThemeUtils.refreshUI(this) } - (findViewById(R.id.select_color_recycler_view) as RecyclerView).apply { + (findViewById(R.id.select_color_recycler_view)).apply { addItemDecoration(HorizontalSpacesDecoration(0, 0, 12.dpToPx(), 12.dpToPx(), false)) layoutManager = MyLinearLayoutManager( this@TranslucentThemeActivity, @@ -302,11 +303,11 @@ class TranslucentThemeActivity : BaseActivity(), View.OnClickListener, OnSeekBar } alpha = appPreferences.translucentBackgroundAlpha blur = appPreferences.translucentBackgroundBlur - (findViewById(R.id.alpha) as SeekBar).apply { + (findViewById(R.id.alpha)).apply { progress = this@TranslucentThemeActivity.alpha setOnSeekBarChangeListener(this@TranslucentThemeActivity) } - (findViewById(R.id.blur) as SeekBar).apply { + (findViewById(R.id.blur)).apply { progress = this@TranslucentThemeActivity.blur setOnSeekBarChangeListener(this@TranslucentThemeActivity) } diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/DefaultSlideView.java b/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/DefaultSlideView.java new file mode 100644 index 00000000..e8041332 --- /dev/null +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/DefaultSlideView.java @@ -0,0 +1,134 @@ +package com.huanchengfly.tieba.post.ui.slideback; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; + +import androidx.annotation.NonNull; + +public class DefaultSlideView implements ISlideView { + private final int arrowWidth; + private final int width; + //private LinearGradient shader; + private final int height; + private Path bezierPath; + private Paint paint, arrowPaint; + private int backViewColor = 0xff000000; + private int arrowColor = Color.WHITE; + + + public DefaultSlideView(@NonNull Context context) { + width = Utils.d2p(context, 50); + height = Utils.d2p(context, 200); + arrowWidth = Utils.d2p(context, 4); + init(context); + } + + public void setBackViewColor(int backViewColor) { + this.backViewColor = backViewColor; + } + + public void setArrowColor(int arrowColor) { + this.arrowColor = arrowColor; + } + + private void init(Context context) { + bezierPath = new Path(); + + paint = new Paint(); + paint.setAntiAlias(true); + paint.setStyle(Paint.Style.FILL); + paint.setColor(backViewColor); + paint.setStrokeWidth(Utils.d2p(context, 1.5f)); + + arrowPaint = new Paint(); + arrowPaint.setAntiAlias(true); + arrowPaint.setStyle(Paint.Style.FILL_AND_STROKE); + arrowPaint.setColor(arrowColor); + arrowPaint.setStrokeWidth(Utils.d2p(context, 1.5f)); + arrowPaint.setStrokeCap(Paint.Cap.ROUND); + } + + + @Override + public boolean scrollVertical() { + return true; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public void onDraw(Canvas canvas, float currentWidth, int orientation) { + float height = getHeight(); + int maxWidth = getWidth(); + float centerY = height / 2; + + float progress = currentWidth / maxWidth; + if (progress == 0) { + return; + } + + paint.setColor(backViewColor); + paint.setAlpha((int) (200 * progress)); + + //画半弧背景 + /* + ps: 小点为起始点和结束点,星号为控制点 + · + | + * + * + | + · + | + * + * + | + · + */ + + float bezierWidth = currentWidth / 2; + bezierPath.reset(); + bezierPath.moveTo(0, 0); + bezierPath.cubicTo(0, height / 4f, bezierWidth, height * 3f / 8, bezierWidth, centerY); + bezierPath.cubicTo(bezierWidth, height * 5f / 8, 0, height * 3f / 4, 0, height); + canvas.drawPath(bezierPath, paint); + + + arrowPaint.setColor(arrowColor); + arrowPaint.setAlpha((int) (255 * progress)); + + //画箭头 + float arrowStart, arrowEnd; + if (orientation == SlideBackView.ORIENTATION_RIGHT) { + arrowStart = currentWidth / 6; + arrowEnd = arrowStart + (arrowWidth * (progress - 0.7f) / 0.3f); + } else { + arrowStart = currentWidth / 6; + arrowEnd = arrowStart - (arrowWidth * (progress - 0.7f) / 0.3f); + } + if (progress <= 0.2) { + //ingore + } else if (progress <= 0.7f) { + //起初变长竖直过程 + float newProgress = (progress - 0.2f) / 0.5f; + canvas.drawLine(arrowStart, centerY - arrowWidth * newProgress, arrowStart, centerY + arrowWidth * newProgress, arrowPaint); + } else { + //后面变形到完整箭头过程 + canvas.drawLine(arrowEnd, centerY - arrowWidth, arrowStart, centerY, arrowPaint); + canvas.drawLine(arrowStart, centerY, arrowEnd, centerY + arrowWidth, arrowPaint); + } + + + } +} diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/ISlideView.java b/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/ISlideView.java new file mode 100644 index 00000000..ca25d668 --- /dev/null +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/ISlideView.java @@ -0,0 +1,35 @@ +package com.huanchengfly.tieba.post.ui.slideback; + +import android.graphics.Canvas; + +public interface ISlideView { + /** + * 是否可以垂直滑动 + * + * @return + */ + boolean scrollVertical(); + + /** + * 宽度 + * + * @return + */ + int getWidth(); + + /** + * 高度 + * + * @return + */ + int getHeight(); + + /** + * 绘制 + * + * @param canvas + * @param currentWidth 根据手指滑动得出的当前宽度(最大值为getWidth()) + * @param orientation 滑动方向 + */ + void onDraw(Canvas canvas, float currentWidth, int orientation); +} diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/OnSlide.java b/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/OnSlide.java new file mode 100644 index 00000000..5b81f6df --- /dev/null +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/OnSlide.java @@ -0,0 +1,5 @@ +package com.huanchengfly.tieba.post.ui.slideback; + +public interface OnSlide { + void onSlideBack(); +} diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/SlideBack.java b/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/SlideBack.java new file mode 100644 index 00000000..7ae9a07c --- /dev/null +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/SlideBack.java @@ -0,0 +1,62 @@ +package com.huanchengfly.tieba.post.ui.slideback; + +import android.app.Activity; + +import androidx.annotation.NonNull; + +public class SlideBack { + private ISlideView slideView; //样式 + private OnSlide onSlide; //滑动监听 + private int canSlideWidth; //左边触发距离 + + public static SlideBack create() { + return new SlideBack(); + } + + /** + * 滑动返回样式 + * + * @param slideView the slide view + * @return the slide back + */ + public SlideBack slideView(ISlideView slideView) { + this.slideView = slideView; + return this; + } + + /** + * 左边开始触发距离 + * + * @param canSlideWidth the can slide width + * @return the slide back + */ + public SlideBack canSlideWidth(int canSlideWidth) { + this.canSlideWidth = canSlideWidth; + return this; + } + + /** + * 滑动触发监听 + * + * @param onSlide the on slide + * @return the slide back + */ + public SlideBack onSlide(OnSlide onSlide) { + this.onSlide = onSlide; + return this; + } + + + public SlideControlLayout attachToActivity(@NonNull Activity activity) { + if (slideView == null) { + slideView = new DefaultSlideView(activity); + } + + if (canSlideWidth == 0) { + canSlideWidth = Utils.d2p(activity, 18); + } + + return new SlideControlLayout(activity, canSlideWidth, slideView, onSlide) + .attachToActivity(activity); + } +} diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/SlideBackView.java b/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/SlideBackView.java new file mode 100644 index 00000000..1a8f017f --- /dev/null +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/SlideBackView.java @@ -0,0 +1,96 @@ +package com.huanchengfly.tieba.post.ui.slideback; + +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.view.View; +import android.view.animation.DecelerateInterpolator; + +import androidx.annotation.NonNull; + +@SuppressLint("ViewConstructor") +public class SlideBackView extends View { + public static final int ORIENTATION_LEFT = 0; + public static final int ORIENTATION_RIGHT = 1; + private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator(); + private ISlideView slideView; + private ValueAnimator animator; + private float rate = 0;//曲线的控制点 + private int orientation = 0;//滑动方向 + + SlideBackView(Context context, @NonNull ISlideView slideView) { + super(context); + setSlideView(slideView); + } + + public ISlideView getSlideView() { + return slideView; + } + + public SlideBackView setSlideView(@NonNull ISlideView slideView) { + this.slideView = slideView; + setLayoutParams(new SlideControlLayout.LayoutParams(slideView.getWidth(), slideView.getHeight())); + return this; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + slideView.onDraw(canvas, rate, orientation); + } + + public void updateOrientation(int orientation) { + this.orientation = orientation; + } + + public void updateRate(float updateRate, boolean hasAnim) { + if (updateRate > getWidth()) { + updateRate = getWidth(); + } + if (rate == updateRate) { + return; + } + cancelAnim(); + if (!hasAnim) { + rate = updateRate; + invalidate(); + if (rate == 0) { + setVisibility(GONE); + } else { + setVisibility(VISIBLE); + } + } + + animator = ValueAnimator.ofFloat(rate, updateRate); + animator.setDuration(200); + animator.addUpdateListener(animation -> { + rate = (Float) animation.getAnimatedValue(); + postInvalidate(); + if (rate == 0) { + setVisibility(GONE); + } else { + setVisibility(VISIBLE); + } + + }); + animator.setInterpolator(DECELERATE_INTERPOLATOR); + animator.start(); + } + + private void cancelAnim() { + if (animator != null && animator.isRunning()) { + animator.cancel(); + } + } + + @Override + protected void onDetachedFromWindow() { + cancelAnim(); + if (rate != 0) { + rate = 0; + invalidate(); + } + super.onDetachedFromWindow(); + } +} diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/SlideControlLayout.java b/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/SlideControlLayout.java new file mode 100644 index 00000000..02cc0bf5 --- /dev/null +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/SlideControlLayout.java @@ -0,0 +1,139 @@ +package com.huanchengfly.tieba.post.ui.slideback; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.view.MotionEvent; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; + +@SuppressLint("ViewConstructor") +public class SlideControlLayout extends FrameLayout { + private final SlideBackView slideBackView; + private final OnSlide onSlide; + private final int canSlideWidth; + private final boolean enable = true; + + private float downX; + private float moveX; + private boolean startDrag = false; + + SlideControlLayout(@NonNull Context context, int canSlideWidth, ISlideView slideView, OnSlide onSlide) { + super(context); + this.canSlideWidth = canSlideWidth; + this.onSlide = onSlide; + slideBackView = new SlideBackView(context, slideView); + addView(slideBackView); + } + + + SlideControlLayout attachToActivity(@NonNull Activity activity) { + ViewParent parent = getParent(); + if (parent instanceof ViewGroup) { + ((ViewGroup) parent).removeView(this); + } + ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView(); + + decor.addView(this, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + return this; + } + + private void onBack() { + if (onSlide == null) { + Utils.getActivityContext(getContext()).onBackPressed(); + } else { + onSlide.onSlideBack(); + } + } + + + private void setSlideViewY(SlideBackView view, int y) { + if (!view.getSlideView().scrollVertical()) { + scrollTo(0, 0); + return; + } + scrollTo(0, -(y - view.getHeight() / 2)); + } + + //region 手势控制 + @Override + public boolean onInterceptTouchEvent(MotionEvent motionEvent) { + if (!enable) { + return false; + } + + switch (motionEvent.getAction()) { + case MotionEvent.ACTION_DOWN: + if (motionEvent.getRawX() <= canSlideWidth) { + return true; + } + if (motionEvent.getRawX() >= Utils.getScreenWidth(getContext()) - canSlideWidth) { + return true; + } + } + return super.onInterceptTouchEvent(motionEvent); + } + + @Override + public boolean onTouchEvent(MotionEvent motionEvent) { + if (!enable) { + return super.onTouchEvent(motionEvent); + } + + float currentX = motionEvent.getRawX(); + + switch (motionEvent.getAction()) { + case MotionEvent.ACTION_DOWN: + float currentY = motionEvent.getRawY(); + if (currentY > Utils.d2p(getContext(), 100)) { + if (currentX <= canSlideWidth) { + setRotationY(0f); + downX = currentX; + startDrag = true; + slideBackView.updateRate(0, false); + slideBackView.updateOrientation(SlideBackView.ORIENTATION_RIGHT); + setSlideViewY(slideBackView, (int) (motionEvent.getRawY())); + } else if (currentX >= Utils.getScreenWidth(getContext()) - canSlideWidth) { + setRotationY(180f); + downX = currentX; + startDrag = true; + slideBackView.updateRate(0, false); + slideBackView.updateOrientation(SlideBackView.ORIENTATION_LEFT); + setSlideViewY(slideBackView, (int) (motionEvent.getRawY())); + } + } + break; + + case MotionEvent.ACTION_MOVE: + if (startDrag) { + moveX = currentX - downX; + if (Math.abs(moveX) <= slideBackView.getWidth() * 2) { + slideBackView.updateRate(Math.abs(moveX) / 2, false); + } else { + slideBackView.updateRate(slideBackView.getWidth(), false); + } + setSlideViewY(slideBackView, (int) (motionEvent.getRawY())); + } + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_OUTSIDE: + if (startDrag && Math.abs(moveX) >= slideBackView.getWidth() * 2) { + onBack(); + slideBackView.updateRate(0, false); + } else { + slideBackView.updateRate(0, startDrag); + } + moveX = 0; + startDrag = false; + break; + } + + return startDrag || super.onTouchEvent(motionEvent); + } + //endregion +} diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/Utils.java b/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/Utils.java new file mode 100644 index 00000000..87ec7226 --- /dev/null +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/slideback/Utils.java @@ -0,0 +1,48 @@ +package com.huanchengfly.tieba.post.ui.slideback; + +import android.app.Activity; +import android.content.Context; +import android.content.ContextWrapper; +import android.graphics.Color; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.WindowManager; + +import androidx.annotation.ColorInt; + +public class Utils { + /** + * 屏幕宽度(像素) + */ + private static int screentwidth; + + @ColorInt + static int setColorAlpha(int color, float alpha) { + color = Color.argb((int) (alpha * 255), Color.red(color), Color.green(color), Color.blue(color)); + return color; + } + + static int d2p(Context var0, float var1) { + DisplayMetrics var2 = var0.getResources().getDisplayMetrics(); + return (int) TypedValue.applyDimension(1, var1, var2); + } + + static int getScreenWidth(Context context) { + if (screentwidth > 0) + return screentwidth; + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + DisplayMetrics outMetrics = new DisplayMetrics(); + wm.getDefaultDisplay().getMetrics(outMetrics); + return screentwidth = outMetrics.widthPixels; + } + + static Activity getActivityContext(Context context) { + if (context == null) + return null; + else if (context instanceof Activity) + return (Activity) context; + else if (context instanceof ContextWrapper) + return getActivityContext(((ContextWrapper) context).getBaseContext()); + return null; + } +}