【问题标题】:Navigation drawer lags when opening and closing android打开和关闭android时导航抽屉滞后
【发布时间】:2022-03-19 00:17:49
【问题描述】:

我正试图让我的导航抽屉平稳运行,因为在打开和关闭抽屉时存在过渡/延迟。我希望它能够完美运行。有什么帮助吗?

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        final MediaPlayer mp = MediaPlayer.create(this, R.raw.firsteps);
        mp.start();


        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.setDrawerListener(toggle);
        toggle.syncState();

        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.setItemIconTintList(null);
        navigationView.setNavigationItemSelectedListener(this);


        FragmentManager fm = getSupportFragmentManager();
        fm.beginTransaction().replace(R.id.content_frame, new MainFragment()).commit();

    }

    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            startActivity(new Intent(getApplicationContext(),Testing.class));
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {

        //final MediaPlayer mp = MediaPlayer.create(this, R.raw.xlophone);

        FragmentManager fm = getSupportFragmentManager();

        int id = item.getItemId();

        if (id == R.id.car_stories) {

            fm.beginTransaction().replace(R.id.content_frame,new ChildrensList()).commit();
            //mp.start();
        } else if (id == R.id.car_places) {

            fm.beginTransaction().replace(R.id.content_frame,new ImportFragment()).commit();
            //mp.start();

        } else if (id == R.id.nav_slideshow) {

        } else if (id == R.id.nav_manage) {

        } else if (id == R.id.nav_share) {

        } else if (id == R.id.nav_send) {

        }

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }
}

【问题讨论】:

    标签: android android-fragments navigation-drawer


    【解决方案1】:

    文档:Click

    试试这个:
    //使用Handler().postDelayed

      @Override
      public boolean onNavigationItemSelected(MenuItem item) {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                 switch (item.getItemId()) {
                     case: R.id.example1:
                           // do something
                           break;
                     case: R.id.example2:
                           // do something
                           break;
                     default: // do something
            }
         }, 200);
         drawer.closeDrawer(GravityCompat.START);
         return true;
      }
    

    以我的拙见,您需要避免每次点击都称“新”。

    要解决此问题,您可以将常量值用于导航抽屉的 android:layout_widthandroid:layout_height 属性即。

            android:layout_width="@dimen/navigation_drawer_width"
            android:layout_height="match_parent"
    

    您可能还想对AndroidManifest.xml 中的活动启用硬件加速

              <activity
                  android:name=".ui.SomeActivity"
                  android:hardwareAccelerated="true" />
    

    【讨论】:

    • 是的,处理程序帮助了我,所以我支持你,但是这种加速并没有增强,所以就是这样。我对这个调用 new 和 const 值不太了解。
    【解决方案2】:

    延迟是由同一线程(主线程也称为 UI 线程)中发生的两个繁重操作(片段替换和抽屉动画)引起的。

    解决此问题的一种方法是在抽屉完全关闭后调用片段替换。这样两个操作就不会同时发生了。

    此外,使用片段容器交叉淡入淡出进度条是一个很好的设计实现。

    在您的 Activity 中,您应该有这样的内容:

    override fun onNavigationItemSelected(item: MenuItem): Boolean {
    
        // Show progress bar and hide content container
        crossfade(progressBar, container, false)
    
        drawerLayout?.addDrawerListener(object : DrawerLayout.DrawerListener {
            override fun onDrawerSlide(drawerView: View, slideOffset: Float) {}
            override fun onDrawerOpened(drawerView: View) {}
            override fun onDrawerStateChanged(newState: Int) {}
            override fun onDrawerClosed(drawerView: View) {
                // This method will be called after drawer animation finishes
                // Perform the fragment replacement
                when (item.itemId) {
                    R.id.drawer_item_1 -> {
                        supportFragmentManager.beginTransaction()
                                .replace(R.id.container, MyFragmentOne.newInstance())
                                .addToBackStack(null)
                                .commit()
                    }
                    R.id.drawer_item_2 -> {
                        supportFragmentManager.beginTransaction()
                                .replace(R.id.container, MyFragmentTwo.newInstance())
                                .addToBackStack(null)
                                .commit()
                    }
                }
    
                // Cross fade back the content container and hide progress bar
                crossfade(container, progressBar, false)
    
                // Remove this listener so close by, for example, swiping do not call it again
                drawerLayout.removeDrawerListener(this)
            }
        })
    
        // Closes the drawer, triggering the listener above
        drawerLayout.closeDrawer(GravityCompat.START)
        return true
    }
    
    private fun crossfade(viewIn: View, viewOut: View, animateViewOut: Boolean = true) {
    
        val crossfadeDuration = 200L
    
        // Set the content view to 0% opacity but visible, so that it is visible
        // (but fully transparent) during the animation.
        viewIn.alpha = 0f
        viewIn.visibility = View.VISIBLE
        viewIn.bringToFront()
    
        // Animate the in view to 100% opacity, and clear any animation
        // listener set on the view.
        viewIn.animate()
                .alpha(1f)
                .setDuration(crossfadeDuration)
                .setListener(null)
    
        // Animate the out view to 0% opacity. After the animation ends,
        // set its visibility to GONE as an optimization step (it won't
        // participate in layout passes, etc.)
        viewOut.animate()
                .alpha(0f)
                .setDuration(if (animateViewOut) crossfadeDuration else 0)
                .setListener(object : AnimatorListenerAdapter() {
                    override fun onAnimationEnd(animation: Animator) {
                        viewOut.visibility = GONE
                    }
                })
    
    }
    

    在你的 xml 中,你应该有这样的东西:

    ...
    <android.support.v4.widget.DrawerLayout
        android:id="@+id/drawerLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:openDrawer="start">
    
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <FrameLayout
                android:id="@+id/container"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:visibility="gone" />
    
            <ProgressBar
                android:id="@+id/progressBar"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:visibility="gone" />
    
        </FrameLayout>
    
        <android.support.design.widget.NavigationView
            android:id="@+id/navigationView"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            app:menu="@menu/drawer" />
    
    </android.support.v4.widget.DrawerLayout>
    ....
    

    【讨论】:

    • 我在 SO 中遇到了各种类似的问题。但我发现这个答案很完美。
    • OnBackPressed 使用此代码@Adi 无法正常工作
    • 你所说的“不正确”是什么意思?
    【解决方案3】:

    只是延迟关闭抽屉,它使关闭动画流畅

    navigation.setNavigationItemSelectedListener { menuItem ->
    
                // make closing side-menu smooth
                Completable.timer(100, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
                    .subscribe {
                        drawer.closeDrawer(GravityCompat.START)
                    }.addTo(disposable)
    
                when(menuItem.itemId){
                    R.id.sideMenuDashboard ->
                        navController.navigate(R.id.fragment1)
                    R.id.sideMenuProfile ->
                        navController.navigate(R.id.fragment2)
                }
                true
            }
    

    【讨论】:

      【解决方案4】:

      调用drawerLayout.closeDrawers()后创建一个新线程

      new Thread(new Runnable() {
      public void run() {
      try {
           TimeUnit.MILLISECONDS.sleep(300);
           //Here call you fragmentManager
          } catch (InterruptedException e) {
           e.printStackTrace();
                          }
         }
       }).start();
      

      当然,您可以根据需要改变 MILISECONDS。对不起我的英语

      【讨论】:

        【解决方案5】:

        延迟是由同一线程(主线程也称为 UI 线程)中发生的两个繁重操作(片段替换和抽屉动画)引起的。

        在我的情况下,导航标题背景图像尺寸很大,因此它适用于高性能设备,但不适用于低性能设备。

        【讨论】:

          猜你喜欢
          • 2022-08-18
          • 1970-01-01
          • 1970-01-01
          • 2014-10-21
          • 1970-01-01
          • 1970-01-01
          • 2023-04-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多