实现新闻频道管理
Posted 天耀106
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现新闻频道管理相关的知识,希望对你有一定的参考价值。
第四节
主activity
package com.tian.yao.four.channel
import android.util.Log
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.listener.OnItemClickListener
import com.tian.yao.BR
import com.tian.yao.R
import com.tian.yao.databinding.ActivityChannelBinding
import com.tian.yao.four.BaseActivity
import com.tian.yao.two.ToastUtils
class ChannelActivity : BaseActivity<ChannelViewModel, ActivityChannelBinding>(),OnItemClickListener{
/**
* 动画时长
*/
private val animDuration: Long = 300
override fun layoutId(): Int {
return R.layout.activity_channel
}
override fun initVariableId(): Int {
return BR.channelViewModel
}
override fun initSetup() {
mViewModel.initData()
mBinding.apply {
channelAction = mViewModel.channelAction
gvUser.layoutManager= GridLayoutManager(this@ChannelActivity,4)
gvUser.adapter = mViewModel.mUserAdapter
mViewModel.mUserAdapter.setOnItemClickListener(this@ChannelActivity)
gvOther.layoutManager= GridLayoutManager(this@ChannelActivity,4)
gvOther.adapter = mViewModel.mOtherAdapter
mViewModel.mOtherAdapter.setOnItemClickListener(this@ChannelActivity)
mViewModel.moreFlag.observe(this@ChannelActivity,{
tvMore.visibility = if(it) View.VISIBLE else View.GONE
gvOther.visibility = if(it) View.VISIBLE else View.GONE
ivEdit.setImageResource(if(it) R.drawable.svg_ok else R.drawable.svg_edit)
})
}
}
override fun onItemClick(adapter: BaseQuickAdapter<*, *>, view: View, position: Int) {
//判断是否是编辑态
//如果是编辑态则点击的时候处理增加/删除操作
//如果不是编辑态则弹出Toast提示,实际使用中可以换成频道详情页的跳转
if (ChannelAdapter.isEdit()) {
var currentView: RecyclerView //currentView表示当前被点击的对象
var anotherView: RecyclerView //anotherView表示另一个对象
if (adapter == mBinding.gvUser.adapter) {
currentView = mBinding.gvUser
anotherView = mBinding.gvOther
} else {
currentView = mBinding.gvOther
anotherView = mBinding.gvUser
}
//计算起点,获取点击View的坐标
var startPos = IntArray(2)
var endPos = IntArray(2)
view.getLocationInWindow(startPos)
var currentAdapter = currentView.adapter as ChannelAdapter
var anotherAdapter = anotherView.adapter as ChannelAdapter
//标记点击的item待删除,并添加到anotherView中
Log.i("wltest", "onItemClick: "+currentAdapter.getItem(position))
anotherAdapter.setTranslating(true)
anotherAdapter.add(currentAdapter.setRemove(position))
var cloneView = mViewModel.getCloneView(view)
currentView.post(Runnable {
(window.decorView as ViewGroup).addView(cloneView,ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT)
var lastView = anotherView.getChildAt(anotherView.childCount - 1)
lastView.getLocationInWindow(endPos)
mViewModel.moveAnimation(cloneView, startPos, endPos, animDuration)
})
} else {
ToastUtils.showShortText(mViewModel.mUserList[position])
}
}
}
viewModel层:
package com.tian.yao.four.channel
import android.app.Application
import android.graphics.Bitmap
import android.graphics.Canvas
import android.view.View
import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.TranslateAnimation
import android.widget.ImageView
import androidx.lifecycle.MutableLiveData
import com.tian.yao.four.BaseViewModel
import org.json.JSONObject
import java.nio.charset.Charset
class ChannelViewModel(application: Application) : BaseViewModel(application) {
private val fileName="channel.json"
var mUserList = ArrayList<String>()
var mOtherList = ArrayList<String>()
lateinit var mUserAdapter: ChannelAdapter
lateinit var mOtherAdapter: ChannelAdapter
var moreFlag = MutableLiveData<Boolean>()
fun initData(){
initJsonData()
initAdapter()
}
private fun initJsonData(){
var inputStream = resources.assets.open(fileName)
val length = inputStream.available()
val buffer = ByteArray(length)
inputStream.read(buffer)
val result = String(buffer, Charset.defaultCharset())
val jsonObject = JSONObject(result)
val userArray = jsonObject.optJSONArray("user")
val otherArray = jsonObject.optJSONArray("other")
for (index in 1..userArray.length()){
mUserList.add( userArray.getString(index-1))
}
for (index in 1..otherArray.length()){
mOtherList.add( otherArray.getString(index-1))
}
}
private fun initAdapter(){
mUserAdapter = ChannelAdapter(true)
mUserAdapter.setNewInstance(mUserList)
mOtherAdapter = ChannelAdapter(false)
mOtherAdapter.setNewInstance(mOtherList)
}
val channelAction=object :ChannelAction{
override fun edit() {
toggleEditState()
}
}
private fun toggleEditState() {
val isEdit = ChannelAdapter.isEdit()
ChannelAdapter.setEdit(!isEdit)
moreFlag.value= !isEdit
mUserAdapter.notifyDataSetChanged()
mOtherAdapter.notifyDataSetChanged()
}
/**
* 移动动画
* @param moveView View 移动的目标View
* @param startPos FloatArray 起点坐标
* @param endPos FloatArray 终点坐标
* @param duration Long 动画时长
*/
fun moveAnimation(moveView: View, startPos: IntArray, endPos: IntArray, duration: Long) {
//1、创建动画,设置起点和终点的坐标
var animation = TranslateAnimation(startPos[0].toFloat(), endPos[0].toFloat(),
startPos[1].toFloat(), endPos[1].toFloat()
)
//2、设置动画时长
animation.duration = duration
//3、设置不停留
animation.fillAfter = false
//4、设置监听器
animation.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation?) {
}
override fun onAnimationEnd(animation: Animation?) {
(moveView.parent as ViewGroup).removeView(moveView)
resetAdapter()
}
override fun onAnimationRepeat(animation: Animation?) {
}
})
//5、启动动画
moveView.startAnimation(animation)
}
private fun resetAdapter() {
mUserAdapter.setTranslating(false)
mOtherAdapter.setTranslating(false)
mUserAdapter.remove()
mOtherAdapter.remove()
}
fun getCloneView(view: View): ImageView {
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
view.draw(canvas)
var imageView = ImageView(view.context)
imageView.setImageBitmap(bitmap)
return imageView
}
}
适配器:
package com.tian.yao.four.channel
import android.widget.TextView
import androidx.core.content.ContextCompat
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.tian.yao.R
class ChannelAdapter : BaseQuickAdapter<String, BaseViewHolder> {
private var mReadyToRemove: Int = -1 //标记预备删除的元素序号
private var mIsUser: Boolean = true
private var mAnimState = AnimState.IDEL
constructor(isUser: Boolean) : super(R.layout.adapter_channel_item) {
mIsUser = isUser
}
/**
* 动画状态枚举,用于对不通的动画状态进行处理,当前只支持空闲和移动
* 目前看也可以用boolean,enum是为了后续扩展
*/
enum class AnimState {
IDEL,
TRANSLATING
}
companion object {
private var mIsEditState: Boolean = false
fun setEdit(isEdit: Boolean) {
mIsEditState = isEdit
}
fun isEdit(): Boolean {
return mIsEditState
}
}
fun add(channelName: String) {
data.add(channelName)
notifyDataSetChanged()
}
/**
* 添加删除标记
* @param index Int 待删除的序号
*/
fun setRemove(index: Int): String {
mReadyToRemove = index
notifyDataSetChanged()
return data[index]
}
fun setTranslating(translating: Boolean) {
mAnimState = if (translating) AnimState.TRANSLATING else AnimState.IDEL
}
fun remove() {
if (mReadyToRemove > 0 && mReadyToRemove < data.size) {
removeAt(mReadyToRemove)
}
mReadyToRemove = -1
notifyDataSetChanged()
}
override fun convert(holder: BaseViewHolder, item: String) {
var tvItem = holder.getView<TextView>(R.id.tv_item)
tvItem.text = item
if (mIsEditState) {
holder.setVisible(R.id.iv_icon, true)
holder.setImageDrawable(
R.id.iv_icon,
if (mIsUser)
ContextCompat.getDrawable(context, R.drawable.svg_subtraction)
else
ContextCompat.getDrawable(context, R.drawable.svg_add)
)
} else {
holder.setVisible(R.id.iv_icon, false)
}
// 1、第一个条件处理currentView的状态
// 2、第二个条件处理anotherView的状态
if (mReadyToRemove == getItemPosition(item) || (mAnimState == AnimState.TRANSLATING && getItemPosition(item) == itemCount - 1)) {
tvItem.text = ""
holder.setVisible(R.id.iv_icon, false)
} else {
tvItem.text = item
}
}
}
点击Action接口:
package com.tian.yao.four.channel
interface ChannelAction {
fun edit()
}
主布局:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="channelViewModel"
type="com.tian.yao.four.channel.ChannelViewModel" />
<variable
name="channelAction"
type="com.tian.yao.four.channel.ChannelAction" />
<import type="android.view.View"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我的频道"
android:textSize="18sp" />
<ImageView
android:id="@+id/iv_edit"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_alignParentEnd="true"
android:onClick="@{v->channelAction.edit()}"
android:padding="2dp"
app:srcCompat="@drawable/svg_edit" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="15dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/gv_user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:layout_marginEnd="14dp"
android:gravity="center"
android:horizontalSpacing="14dp"
android:numColumns="4"
android:scrollbars="vertical"
android:stretchMode="columnWidth"
android:verticalSpacing="14dp" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="10dp" />
<TextView
android:id="@+id/tv_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="15dp"
android:text="更多频道"
android:visibility="gone"
android:textSize="18sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/gv_other"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:layout_marginEnd="14dp"
android:gravity="center"
android:visibility="gone"
android:horizontalSpacing="14dp"
android:numColumns="4"
android:scrollbars="vertical"
android:stretchMode="columnWidth" />
</LinearLayout>
</layout>
效果图:
此外:我还对 BaseActivity做了自己的初步封装,可以一步步学习~
package com.tian.yao.four
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.ViewModelProvider
import kotlin.reflect.KClass
abstract class BaseActivity<VM : BaseViewModel, DB : ViewDataBinding> : AppCompatActivity() {
lateinit var mBinding: DB
protected val mViewModel: VM by lazy {
val kclazz = (GenericUtil.getClassType(this, BaseViewModel::class) as KClass<VM>).java
val viewModel = ViewModelProvider(this,ViewModelFactory(application)).get(kclazz)
if (initVariableId() > 0) {
mBinding.setVariable(initVariableId(), viewModel)
}
viewModel
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = DataBindingUtil.setContentView(this, layoutId())
mBinding.lifecycleOwner = this
initSetup()
}
abstract fun layoutId(): Int
abstract fun initVariableId(): Int
abstract fun initSetup()
}
BaseViewModel层
package com.tian.yao.four
import android.app.Application
import android.content.res.Resources
import androidx.lifecycle.AndroidViewModel
open class BaseViewModel(application: Application) : AndroidViewModel(application) {
protected val resources: Resources = application.resources
}
ViewModelFactory
package com.tian.yao.four
import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import java.lang.reflect.InvocationTargetException
class ViewModelFactory(private val application: Application) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(BaseViewModel::class.java)) {
return BaseViewModel(application) as T
}
//反射动态实例化ViewModel
return try {
val className = modelClass.canonicalName
val classViewModel = Class.forName(className)
val cons = classViewModel.getConstructor(Application::class.java)
val viewModel = cons.newInstance(application) as ViewModel
viewModel as T
} catch (e: ClassNotFoundException) {
e.printStackTrace()
throw java.lang.IllegalArgumentException("Unknown ViewModel class: " + modelClass.name)
} catch (e: IllegalAccessException) {
e.printStackTrace()
throw java.lang.IllegalArgumentException("Unknown ViewModel class: " + modelClass.name)
} catch (e: InstantiationException) {
e.printStackTrace()
throw java.lang.IllegalArgumentException("Unknown ViewModel class: " + modelClass.name)
} catch (e: NoSuchMethodException) {
e.printStackTrace()
throw java.lang.IllegalArgumentException("Unknown ViewModel class: " + modelClass.name)
} catch (e: InvocationTargetException) {
e.printStackTrace()
throw java.lang.IllegalArgumentException("Unknown ViewModel class: " + modelClass.name)
}
}
}
工具类
package com.tian.yao.four
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import kotlin.reflect.KClass
object GenericUtil {
fun getClassType(obj: Any, destClz: KClass<*>) = getClassType(obj::class.java, destClz.java)
private fun getClassType(clz: Class<*>, destClz: Class<*>): KClass<*>? {
var c = clz
var genType: Type?
while (c.superclass != null) {
genType = c.genericSuperclass
if (genType !is ParameterizedType) {
c = c.superclass as Class<*>
continue
} else {
val types = genType.actualTypeArguments
for (type in types) {
val tClz = type as Class<*>
return if (destClz.isAssignableFrom(tClz)) {
type.kotlin
} else {
continue
}
}
break
}
}
return null
}
}
代码链接:
链接: https://pan.baidu.com/s/1aqpcuhVgIkCr2rfnDV_6ng 提取码: rrea
赞赏码,哈哈哈
以上是关于实现新闻频道管理的主要内容,如果未能解决你的问题,请参考以下文章
iOS 利用UICollectionView拖拽排序 实现的仿照腾讯新闻频道管理功能 XLChannelControl
高仿新闻类APP频道管理功能,ItemTouchHelper的实践
《java精品毕设》基于javaweb宠物领养平台管理系统(源码+毕设论文+sql):主要实现:个人中心,信息修改,填写领养信息,交流论坛,新闻,寄养信息,公告,宠物领养信息,我的寄养信息等(代码片段