feat: 侧边滑动返回 & 两侧支持
This commit is contained in:
parent
d55b0d6df8
commit
5faef59cbc
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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<HotMessageListBean.HotMessageRetBean>? = null
|
||||
) : BaseSingleTypeDelegateAdapter<HotMessageListBean.HotMessageRetBean>(
|
||||
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<TextView>(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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<TintConstraintLayout>(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<View>(R.id.activity_reply_root).setOnClickListener(this)
|
||||
findViewById<View>(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<TabLayout>(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<TintImageView>(R.id.activity_reply_edit_undo)
|
||||
val redo = findViewById<TintImageView>(R.id.activity_reply_edit_redo)
|
||||
val clear = findViewById<TintImageView>(R.id.activity_reply_edit_clear)
|
||||
undo.setOnClickListener(this)
|
||||
setEnabled(undo, false)
|
||||
redo.setOnClickListener(this)
|
||||
|
|
|
|||
|
|
@ -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<View>(R.id.thread_bottom_bar_agree).setOnClickListener(this)
|
||||
findViewById<View>(R.id.thread_reply_bar).setOnClickListener(this)
|
||||
moreBtn.setOnClickListener(this)
|
||||
toolbar.setOnClickListener(this)
|
||||
threadHeaderAdapter.setOnToggleSeeLzListener {
|
||||
|
|
|
|||
|
|
@ -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<View>(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<in Drawable>?) {
|
||||
resource.alpha = alpha
|
||||
val bitmap = ImageUtil.drawableToBitmap(resource)
|
||||
findViewById(R.id.background).background = BitmapDrawable(resources, bitmap)
|
||||
findViewById<View>(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<RecyclerView>(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<SeekBar>(R.id.alpha)).apply {
|
||||
progress = this@TranslucentThemeActivity.alpha
|
||||
setOnSeekBarChangeListener(this@TranslucentThemeActivity)
|
||||
}
|
||||
(findViewById(R.id.blur) as SeekBar).apply {
|
||||
(findViewById<SeekBar>(R.id.blur)).apply {
|
||||
progress = this@TranslucentThemeActivity.blur
|
||||
setOnSeekBarChangeListener(this@TranslucentThemeActivity)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.huanchengfly.tieba.post.ui.slideback;
|
||||
|
||||
public interface OnSlide {
|
||||
void onSlideBack();
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue