<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [TOC] # 1. 前言 也就是使用ListView來做一個類似QQ的每個條目可以側滑出菜單的效果。實現步驟大致為: * 定義好Item的布局,也就是主Item填充整個屏幕的寬度,而對應的側滑出來的Menu就默認不顯示,而放置在屏幕之外; * 為了做到上面的效果,這里需要使用自定義ViewGroup,然后復寫onlayout方法,對Menu進行放置。 * 當然,因為要響應手指的側滑事件,所以這里需要復寫onTouchEvent方法對滑動事件進行處理,使用scrollTo來進行移動。 * 在移動的過程中進行邊界判斷,也就是屏蔽非法值; * 然后為移動添加動態效果,也就是當移動距離大于這個Menu的寬度的一般的時候,就默認打開或者關閉; * 打開或者關閉的效果使用Scroller來進行動態計算,請求重新繪制,然后在computeScroll中進行scrollTo方法的調用。 * 在使用Scroller的時候,注意到移動的距離為目標值減去當前X/Y軸的位置。 * 由于我們是在ListView中進行Item的側滑,故而這里要處理一下滑動沖突問題,也就是如果是橫滑,就請求父控件放行; * 然后需要處理當item的menu展開,有其余非當前item的事件的時候,關閉當前的item。 # 2. 實現 ## 2.1 布局 ``` <com.weizu.sideslip.MyContainer xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="60dp"> <!--主要顯示的內容--> <TextView android:id="@+id/content_title" android:layout_width="match_parent" android:layout_height="60dp" android:background="#33000000" android:text="AAA" android:textSize="24sp" android:gravity="center_vertical" android:paddingLeft="10dp" /> <!--右邊的menu--> <LinearLayout android:layout_width="wrap_content" android:layout_height="60dp" android:orientation="horizontal"> <TextView android:layout_width="match_parent" android:layout_height="60dp" android:background="@color/white" android:textColor="@color/red" android:text="Delete" android:textSize="24sp" android:gravity="center_vertical" android:paddingLeft="10dp" android:paddingRight="10dp" /> </LinearLayout> </com.weizu.sideslip.MyContainer> ``` 而MyContainer也就是這里需要進行復寫onlayout的自定義ViewGroup,這里直接繼承自FrameLayout,因為不必關onmeasure,只需要簡單的進行onLayout即可。當然,因為要處理手指觸摸事件,這里需要復寫onTouchEvent,并在其中判斷橫向或者豎向滑動,如果是橫向滑動,就請求父控件發行。對應的使用Scroller來動態計算移動的位置,即: ~~~ class MyContainer(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) { var itemWidth = 0 var scroller: Scroller = Scroller(context) override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { super.onLayout(changed, left, top, right, bottom) val childView = getChildAt(1) itemWidth = childView.width childView.layout(width, 0, width + itemWidth, childView.height) } var startX = 0f var downX = 0f var downY = 0f override fun onTouchEvent(event: MotionEvent?): Boolean { super.onTouchEvent(event) when(event?.action){ MotionEvent.ACTION_DOWN -> { startX = event.x downX = event.x downY = event.y } MotionEvent.ACTION_MOVE -> { var xAxis = (scrollX - ( event.x - startX)).toInt() if(xAxis > itemWidth) { xAxis = itemWidth } else if(xAxis < 0) { xAxis = 0 } scrollTo(xAxis, 0) startX = event.x // 因為外層ListView可以豎直滑動,而這里的Item可以橫向滑動,所以這里也要處理一下事件 val distanceX = abs(event.x - downX) val distanceY = abs(event.y - downY) if(distanceX > distanceY && distanceX > 8){ parent.requestDisallowInterceptTouchEvent(true) } } MotionEvent.ACTION_UP -> { // 抬起手指就根據位置動畫 if (scrollX > itemWidth / 2) { // 開啟菜單 openMenu() } else { closeMenu() } } } return true } fun openMenu(){ // 目標 - scrollX val dx = itemWidth - scrollX scroller.startScroll(scrollX, scrollY, dx, scrollY) invalidate() } fun closeMenu(){ // 目標 - scrollX val dx = 0 - scrollX scroller.startScroll(scrollX, scrollY, dx, scrollY) invalidate() } override fun computeScroll() { super.computeScroll() if(scroller.computeScrollOffset()){ scrollTo(scroller.currX, scroller.currY) invalidate() } } } ~~~ 首先在上面的類中增加監聽接口,然后處理一下Item的點擊事件,這里需要注意,因為還是會有事件沖突需要處理,因為這里需要對事件攔截,故而復寫onInterceptTouchEvent方法。 完整代碼,首先是自定義VIewGroup: ~~~ class MyContainer(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) { var itemWidth = 0 var scroller: Scroller = Scroller(context) override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { super.onLayout(changed, left, top, right, bottom) val childView = getChildAt(1) itemWidth = childView.width childView.layout(width, 0, width + itemWidth, childView.height) } // 放行點擊事件,因為Item的點擊事件是其子View需要響應 override fun onInterceptTouchEvent(event: MotionEvent?): Boolean { var intercept = false when(event?.action){ MotionEvent.ACTION_DOWN -> { startX = event.x downX = event.x downY = event.y } MotionEvent.ACTION_MOVE -> { val xAxis = (scrollX - ( event.x - startX)).toInt() if(xAxis > 8) { intercept = true // 橫向滑動需要攔截 } } } return intercept } var startX = 0f var downX = 0f var downY = 0f override fun onTouchEvent(event: MotionEvent?): Boolean { super.onTouchEvent(event) when(event?.action){ MotionEvent.ACTION_DOWN -> { startX = event.x downX = event.x downY = event.y mListener?.onDown(this) } MotionEvent.ACTION_MOVE -> { var xAxis = (scrollX - ( event.x - startX)).toInt() if(xAxis > itemWidth) { xAxis = itemWidth } else if(xAxis < 0) { xAxis = 0 } scrollTo(xAxis, 0) startX = event.x // 因為外層ListView可以豎直滑動,而這里的Item可以橫向滑動,所以這里也要處理一下事件 val distanceX = abs(event.x - downX) val distanceY = abs(event.y - downY) if(distanceX > distanceY && distanceX > 8){ parent.requestDisallowInterceptTouchEvent(true) } } MotionEvent.ACTION_UP -> { // 抬起手指就根據位置動畫 if (scrollX > itemWidth / 2) { // 開啟菜單 openMenu() } else { closeMenu() } } } return true } fun openMenu(){ // 目標 - scrollX val dx = itemWidth - scrollX scroller.startScroll(scrollX, scrollY, dx, scrollY) invalidate() mListener?.onOpen(this) } fun closeMenu(){ // 目標 - scrollX val dx = 0 - scrollX scroller.startScroll(scrollX, scrollY, dx, scrollY) invalidate() mListener?.onClose(this) } override fun computeScroll() { super.computeScroll() if(scroller.computeScrollOffset()){ scrollTo(scroller.currX, scroller.currY) invalidate() } } interface OnItemMenuStateChangeListener{ fun onClose(view: MyContainer) fun onDown(view: MyContainer) fun onOpen(view: MyContainer) } private var mListener: OnItemMenuStateChangeListener? = null fun setOnItemChangeListener(l: OnItemMenuStateChangeListener){ mListener = l } } ~~~ 然后是ManActivity: ~~~ /** * 側滑菜單 */ class MainActivity : AppCompatActivity() { val listView by lazy { findViewById<ListView>(R.id.listView) } val datas = mutableListOf<String>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) initDatas() listView.adapter = MyAdapter() } fun initDatas() { for (i in 0 until 30) { datas.add("Content ${i}") } } inner class MyAdapter : BaseAdapter() { override fun getCount() = datas.size override fun getItem(position: Int) = position override fun getItemId(position: Int) = position.toLong() override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { var view: View? = convertView var myViewHolder: MyViewHolder? = null if (convertView == null) { myViewHolder = MyViewHolder() view = View.inflate(this@MainActivity, R.layout.item_layout, null) myViewHolder.textView = view.findViewById<TextView>(R.id.content_title) myViewHolder.delete = view.findViewById<TextView>(R.id.delete) view.setTag(myViewHolder) } else { myViewHolder = convertView.getTag() as MyViewHolder? } myViewHolder?.apply { myViewHolder.textView?.text = datas.get(position) (view as MyContainer).setOnItemChangeListener(MyItemMenuChangeListener()) myViewHolder.textView?.setOnClickListener(object : View.OnClickListener { override fun onClick(v: View?) { Toast.makeText( this@MainActivity, "點擊了:${datas.get(position)}", android.widget.Toast.LENGTH_LONG ).show() } }) // 刪除數據,更新對應的ListView myViewHolder.delete?.setOnClickListener(object : View.OnClickListener { override fun onClick(v: View?) { // 由于ListView中Item的復用機制,會導致當前打開的Item用來顯示下個數據,而實際上我們所 // 期望的是更新的時候,沒有Item的Menu被打開,故而需要調用一次closeMenu ((v?.parent?.parent) as MyContainer).closeMenu() datas.remove(datas.get(position)) notifyDataSetChanged() } }) } return view!! } } inner class MyViewHolder { var textView: TextView? = null var delete: TextView? = null } // 在ListView中上一輪打開的Item var lastMyContainer: MyContainer? = null // inner class MyItemMenuChangeListener : MyContainer.OnItemMenuStateChangeListener { override fun onClose(view: MyContainer) { Log.e("TAG", "onClose: ") if (lastMyContainer == view) { lastMyContainer = null } } override fun onDown(view: MyContainer) { Log.e("TAG", "onDown: ") // 判斷是否是本輪自己的MyContainer,否則就是上輪打開的MyContainer,也就是上輪的Item if (view != lastMyContainer) { lastMyContainer?.closeMenu() } } override fun onOpen(view: MyContainer) { Log.e("TAG", "onOpen: ") // 更新本輪MyContainer的值 lastMyContainer = view } } } ~~~ 至于主布局,也就是一個Linearlayout包一個ListView: ~~~ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> ~~~ 效果: ![](https://img.kancloud.cn/21/24/2124c9d8bcc77492e9d5b154ff2677b0_284x428.png) * 可響應點擊delete刪除該條目; * Content的點擊Toast; * 滑動到一半的自動滾動,關閉或者打開;
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看