【问题标题】:why I can't change toolbar title after using back button (physical back button) in Android?为什么在 Android 中使用后退按钮(物理后退按钮)后无法更改工具栏标题?
【发布时间】:2019-11-29 01:41:10
【问题描述】:

这里是要下载的项目:https://www.dropbox.com/s/lq3p2pnwjacik7s/testApp.zip?dl=0

我使用的是安卓导航组件,下面是应用截图:

如您所见,在 MainActivity 布局中,有一个 nav_host_fragment、一个工具栏和一个底部导航视图。

图中Blue Tab的顺序会是这样的

“CUSTOM TITLE HERE”工具栏中的标题硬编码在destination_blue1 片段中

但是当我从 blue1 移动到 blue2,然后使用后退按钮(物理硬件后退按钮)返回 blue1 时,标题会更改为“fragment_blue1”,而不是“CUSTOM TITLE HERE”(硬编码)。

"fragment_blue1" 实际上是该片段的目标图 id 字符串。

我不明白为什么即使我将标题硬编码为“CUSTOM TITLE HERE”,但如果我使用(物理硬件后退按钮)它就不起作用。

但如果我使用向上按钮(工具栏/操作栏中的后退按钮),那么标题将是“CUSTOM TITLE HERE”,根据我硬编码的标题。

这是当我的硬编码标题不起作用时的标题,当我使用后退按钮(物理后退按钮)从蓝色 2 移回蓝色 1 时。

这是我真实案例的简化,我需要从片段 Blue1 动态更改标题。我不明白为什么使用后退按钮后无法更改标题。但是当使用向上按钮时,标题将按照我使用的代码跟随,与目标ID图不同。

如何解决这个问题?出了什么问题?

我正在使用样式<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">,这是我的 MainActivity 的代码

class MainActivity : AppCompatActivity() {

    lateinit var navController : NavController
    lateinit var toolbar: Toolbar
    lateinit var bottomNavigationView : BottomNavigationView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        navController = Navigation.findNavController(this,R.id.nav_host_fragment)
        setUpViewDeclaration()
        setupBottomNavMenu()
        setupActionBar()


    }

    private fun setUpViewDeclaration() {
        toolbar = findViewById(R.id.toolbar)
        bottomNavigationView = findViewById(R.id.bottom_nav)

    }

    private fun setupBottomNavMenu() {
        bottom_nav.setupWithNavController(navController)
    }

    private fun setupActionBar() {

        // set up top hierarchy destination
        val appBarConfiguration = AppBarConfiguration(setOf(
            R.id.destination_blue1,
            R.id.destination_red1)
        )

        setSupportActionBar(toolbar)
        toolbar.setupWithNavController(navController,appBarConfiguration)

    }
}

这是blue1片段的代码

class Blue1Fragment : Fragment() {

    lateinit var moveButton: Button
    lateinit var fragmentView: View

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        fragmentView = inflater.inflate(R.layout.fragment_blue1, container, false)
        moveButton = fragmentView.findViewById(R.id.move_button_1)

        // The title hard coded in here
        // this one line below seems doesn't work if using back physical button
        (activity as AppCompatActivity).supportActionBar?.title = "CUSTOM TITLE HERE" 



        moveButton.setOnClickListener {

            val nextDestination = Blue1FragmentDirections.actionToBlue2()
            Navigation.findNavController(fragmentView).navigate(nextDestination)

        }

        return fragmentView
    }


}

这是blue2片段的代码:

class Blue2Fragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_blue2, container, false)
    }


}

【问题讨论】:

    标签: android android-architecture-components android-jetpack android-architecture-navigation android-jetpack-navigation


    【解决方案1】:

    尝试在“onViewCreated”中设置标题

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

    【讨论】:

    • 非常感谢,但不幸的是它不起作用。我也尝试将其移至 onResume,但仍然无法正常工作
    【解决方案2】:

    发生这种情况是因为您添加了片段,而添加 onResume 没有调用。如果您的导航很简单(片段之间的路由始终相同),您可以通过在 SecondFragment 中调用 onStop() 来实现它,并在此方法中将工具栏标题更改为第一个片段标题。 如果您的片段动态变化(从 fr1 调用 fr2/fr3),您可以在 bundle 上传递标题并将其替换为您的自定义标题

    //inside Blue2Fragment
    
    override fun onStop() {
        (activity as AppCompatActivity).supportActionBar?.title = "CUSTOM TITLE HERE"
        super.onStop()
    }
    

    【讨论】:

    • 非常感谢,但不幸的是它不起作用。我试图将 onStop 代码放入 Blue2Fragment :(
    • @Alexa289 当您关闭 Blue2Fragment onStop 调用时,您可以在销毁片段之前设置标题,我认为您可以在第一个片段中实现,或者也尝试 onPause,但这没有任何意义。我已经尝试过我的案例,效果很好
    • 非常感谢您的回复。它应该正确执行,对吗? i.stack.imgur.com/eaFHr.png 。如果是,那么不幸的是它仍然无法正常工作。如果我使用后退按钮(右下角的物理后退按钮),标题仍然不是“CUSTOM TITLE HERE”。如果你不介意,你可以通过我的 Dropbox 链接下载上面的项目 :)
    【解决方案3】:

    我不熟悉kotlin,但java 中有一个解决方法,通过动态更改toolbartitlesubTitle 来解决此问题。

    首先,我们需要创建一个对象用作MultableLiveData 类型,带有标题和副标题参数。

    public class Toolbar {
        private String title, subTitle;
    
        public Toolbar(String title, @Nullable String subTitle) {
            this.title = title;
            this.subTitle = subTitle;
        }
    
        public String getTitle() {
            return title;
        }
    
        public String getSubTitle() {
            return subTitle;
        }
    }
    

    MainActivity中,我们将toolbar定义为MultableLiveData并在onCreate()中观察它,并在onDestroy()中移除观察者。

    public MutableLiveData<Toolbar> toolbar = new MutableLiveData<>();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        bottomNavigationView = (BottomNavigationView) findViewById(R.id.main_bottomnav);
        navigationView = (NavigationView) findViewById(R.id.main_sidebar);
        drawerLayout = (DrawerLayout) findViewById(R.id.main_drawer);
    
        setupNavigation();
    
        toolbar.observe(this, new Observer<Toolbar>() {
            @Override
            public void onChanged(Toolbar toolbarModel) {
                getSupportActionBar().setTitle(toolbarModel.getTitle());
                getSupportActionBar().setSubtitle(toolbarModel.getSubTitle());
            }
        });
    
    }
    
    @Override
    protected void onDestroy() {
        toolbar.removeObservers(this);
        super.onDestroy();
    }
    

    在您的任何片段中,我们将toolbars 的标题和副标题设置如下:

    @Override
    public void onStart() {
        super.onStart();
        ((MainActivity) requireActivity()).toolbar.postValue(new Toolbar("MyFragment Title", "MyFragment SubTitle"));
    }
    

    或者

    @Override
    public void onStart() {
        super.onStart();
        ((MainActivity) requireActivity()).toolbar.postValue(new Toolbar("MyFragment Title", null));
    }
    

    还要从您的 nav_graph.xml 中删除 android:label 以避免标题/标签冲突。

    <fragment
        android:id="@+id/shopFragment"
        android:name="com.myapp.ShopFragment"
        android:label="TO BE REMOVED" // REMOVE THIS LINE OF CODE
        tools:layout="@layout/fragment_shop" />
    

    希望对你有帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-10
      • 1970-01-01
      • 1970-01-01
      • 2014-06-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-30
      • 1970-01-01
      相关资源
      最近更新 更多