View->上下弹出式的Fragment

XML文件

  • ItemView布局R.layout.layout_item_view
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <FrameLayout
        android:id="@+id/fl"
        android:layout_width="46dp"
        android:layout_height="46dp"
        android:background="@drawable/shape_dmt_bg"
        android:layout_margin="3dp">
        <ImageView
            android:id="@+id/iv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"/>
    </FrameLayout>
</FrameLayout>
  • Activity布局R.layout.activity_main
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_red_light">
    <FrameLayout
        android:id="@+id/fl_pop_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true" />
</RelativeLayout>
  • Fragment布局R.layout.fragment_my_pop

RecyclerView的相关类

  • ViewHolder代码
class MyViewHolder(itemView: View, private val mListener: OnItemSelectListener?) : RecyclerView.ViewHolder(itemView) , MyListViewHelper.ISelectable {
    private var mIv: ImageView? = null
    private var mFl: FrameLayout? = null

    fun bind(index: Int, type: MyType) {
        mIv = itemView.findViewById(R.id.iv)
        mFl = itemView.findViewById(R.id.fl)
        mIv?.setImageResource(type.icon)
        itemView.setOnClickListener {
            mListener?.onItemSelect(index, type)
        }
    }

    override fun select() {
        mFl?.setBackgroundResource(R.drawable.shape_dmt_bg_on)
        mIv?.setColorFilter(Color.parseColor("#FFFFD800"))
    }

    override fun unselect() {
        mFl?.setBackgroundResource(R.drawable.shape_dmt_bg)
        mIv?.colorFilter = null
    }

    interface OnItemSelectListener {
        fun onItemSelect(index: Int, type: MyType)
    }
}

data class MyType (val icon: Int, val type: TYPE) {
    enum class TYPE {
        A, B, C,
    }
}
  • Adapter代码
class MyAdapter : RecyclerView.Adapter<MyViewHolder>() {
    private val mData = ArrayList<MyType>().apply {
        add(MyType(R.drawable.ic_rect, MyType.TYPE.A))
        add(MyType(R.drawable.ic_crop_free, MyType.TYPE.B))
        add(MyType(R.drawable.ic_icon_crop_rotate, MyType.TYPE.C))
        add(MyType(R.drawable.ic_rect, MyType.TYPE.A))
        add(MyType(R.drawable.ic_crop_free, MyType.TYPE.B))
        add(MyType(R.drawable.ic_icon_crop_rotate, MyType.TYPE.C))
        add(MyType(R.drawable.ic_rect, MyType.TYPE.A))
        add(MyType(R.drawable.ic_crop_free, MyType.TYPE.B))
        add(MyType(R.drawable.ic_icon_crop_rotate, MyType.TYPE.C))
        add(MyType(R.drawable.ic_crop_free, MyType.TYPE.B))
        add(MyType(R.drawable.ic_icon_crop_rotate, MyType.TYPE.C))
    }

    private var mSelectedListener: MyViewHolder.OnItemSelectListener? = null

    fun setOnItemSelectListener(listener: MyViewHolder.OnItemSelectListener) {
        mSelectedListener = listener
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val itemView = LayoutInflater.from(parent.context).inflate(R.layout.layout_item_view, parent, false)
        return MyViewHolder(itemView, mSelectedListener)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        holder.bind(position, mData[position])
    }

    override fun getItemCount(): Int {
        return mData.size
    }
}

动态添加ItemView的工具类

  • 传入RecyclerViewAdapter,在父View中动态添加RecyclerView的每个ItemView(依次调用AdapteronCreateViewHolder方法和onBindViewHolder方法)
class MyListViewHelper(private val mContext : Context, private val mColumns : Int = 5, private val mMarginBottom : Float = 20f) {
    private val mViews = HashMap<Int, RecyclerView.ViewHolder>()
    private var mSelectedIndex = -1

    fun <T : RecyclerView.ViewHolder> setAdapter(parentView: ViewGroup, adapter: RecyclerView.Adapter<T>){
        // 确定要添加的行数
        val rows = Math.ceil(((adapter.itemCount / (mColumns * 1f)).toDouble())).toInt() // 向上取整,确定最大行数
        Log.d("yang", "adapter.itemCount = ${adapter.itemCount}, rows = $rows")
        for (row in 0 until rows) {
            val childLinearLayout = LinearLayout(parentView.context).apply {
                orientation = LinearLayout.HORIZONTAL
            }
            val params = ViewGroup.MarginLayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
            ).apply {
                bottomMargin = dpToPx(mContext, mMarginBottom).toInt()
            }
            // 每一行的Linearlayout开始添加ItemView
            for (column in 0 until mColumns) {
                val index = row * mColumns + column
                val viewHolder: RecyclerView.ViewHolder
                if (index < adapter.itemCount) {
                    viewHolder = adapter.createViewHolder(childLinearLayout, adapter.getItemViewType(index))
                    adapter.bindViewHolder(viewHolder, index)
                    mViews[index] = viewHolder
                } else {
                    // 如果不足一行,补充空白的占位ItemView
                    viewHolder = adapter.createViewHolder(childLinearLayout, 0)
                    viewHolder.itemView.visibility = View.INVISIBLE
                }
                val itemViewParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply {
                    leftMargin = 50
                    rightMargin = 50
                }
                childLinearLayout.addView(viewHolder.itemView, itemViewParams)
            }
            // 添加到父布局的LinearLayout中
            childLinearLayout.gravity = Gravity.CENTER_HORIZONTAL
            parentView.addView(childLinearLayout, params)
        }
    }

    fun performSelect(index: Int) {
        if (index == mSelectedIndex) {
            return
        }
        val vh = mViews[index] ?: return
        vh.itemView.performClick()
    }

    fun select(index: Int) {
        if (index == mSelectedIndex) {
            return
        }
        val vh = mViews[index] ?: return
        val oldVH = mViews[mSelectedIndex]
        (oldVH as ISelectable?)?.unselect()
        (vh as ISelectable).select()
        mSelectedIndex = index
    }

    interface ISelectable {
        fun select()
        fun unselect()
    }
}

Activity代码和Fragment代码

  • Activity代码
class MainActivity : AppCompatActivity() {
    private lateinit var mList: ViewGroup
    private lateinit var mListHelper: MyListViewHelper
    private lateinit var mAdapter : MyAdapter
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mList = findViewById(R.id.list)
        mAdapter = MyAdapter()
        mAdapter.setOnItemSelectListener(object : MyViewHolder.OnItemSelectListener {
            override fun onItemSelect(index: Int, type: MyType) {
                mListHelper.select(index)
            }
        })
        mListHelper = MyListViewHelper(this, 3)
        mListHelper.setAdapter(mList, mAdapter)
        mListHelper.performSelect(0)
    }
}
  • Fragment代码

class MyPopFragment : Fragment() {
    private var mContentView : View? = null
    private var mList: ViewGroup ?= null
    private var mListHelper: MyListViewHelper ?= null
    private var mAdapter : MyAdapter ?= null
    fun show(manager: FragmentManager): MyPopFragment {
        manager.beginTransaction().replace(R.id.fl_pop_container, this, "FRAGMENT_MY_POP").commitAllowingStateLoss()
        return this
    }

    fun restoreToOriginHeight(): ValueAnimator? {
        val contentView = mContentView!!
        val from = contentView.translationY
        val to = max(0f,  0f)
        if (from == to) {
            return null
        }
        val animator = ValueAnimator().apply {
            setFloatValues(from, to)
            duration = 5000
            interpolator = DecelerateInterpolator()
            addUpdateListener {
                contentView.translationY = it.animatedValue as Float
            }
            start()
        }
        return animator
    }


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {
        mContentView = inflater.inflate(R.layout.fragment_my_pop, container, false)
        mContentView?.apply {
            viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
                override fun onPreDraw(): Boolean {
                    viewTreeObserver.removeOnPreDrawListener(this)
                    // 下面代码只执行一次
                    translationY = -measuredHeight.toFloat()
                    restoreToOriginHeight()
                    return true
                }
            })
        }

        return mContentView
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        mList = mContentView?.findViewById(R.id.list)
        mAdapter = MyAdapter()
        mAdapter?.setOnItemSelectListener(object : MyViewHolder.OnItemSelectListener {
            override fun onItemSelect(index: Int, type: MyType) {
                mListHelper?.select(index)
            }
        })
        context?.let {
            mListHelper = MyListViewHelper(it, 3)
        }
        mListHelper?.setAdapter(mList!!, mAdapter!!)
        mListHelper?.performSelect(0)
    }
}

效果图

在这里插入图片描述

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值