原始问题
在我正在编写的 Beamer 演示文稿中,我有一个itemize
列表,并希望逐一显示每个项目。然后,在幻灯片上出现给定项目后,我希望以透明的方式重新覆盖该项目。使用 很容易实现这again covered
一点\setbeamercovered
:
\documentclass{beamer}
\setbeamercovered{again covered={\opaqueness<1->{25}}}
\begin{document}
\begin{frame}{Frame Title}
\begin{itemize}[<+>]
\item Who's on first
\item What's on second
\item I don't know's on third
\end{itemize}
\uncover<+->{-- Abbott and Costello}
\end{frame}
\end{document}
但这里有一个转折:我想修改上面的例子,这样,一旦被覆盖,单词“Who”、“What”、“I don't know”即使在它们各自的\item
s 被重新覆盖后仍然未被覆盖。以下代码尝试了三种不同的方法来实现这一点:
\documentclass{beamer}
\setbeamercovered{again covered={\opaqueness<1->{25}}}
\begin{document}
\begin{frame}{Frame Title}
\begin{itemize}[<+>]
\item \uncover<.->{Who}'s on first
\item {\color<.->{black} What}'s on second
\item<+-> I don't know\uncover<.>{'s on third}
\end{itemize}
\uncover<+->{-- Abbott and Costello}
\end{frame}
\end{document}
前两次尝试根本不起作用。第三次尝试更接近,但仍然不太正确:我希望三角形项目标记在's on third
被重新覆盖时保持透明。
所以,我的问题是:即使周围上下文被重新覆盖,我怎样才能干净而正确地保持某些子短语不被覆盖?
可能有一种方法可以挂接到项目标记并使其透明,但我想避免这种情况;我将使用带有推理规则的答案(用包设置lkproof
),由于我的 TeX 知识有限,因此很难创建这样的钩子。
修改后的问题
@alexurba 的答案很有用,几乎满足了我的需求,但还不够。首先,我稍微修改了他的建议:
\newcommand<>{\myuncover}[1]{%
\alt#2{\mbox{\beamer@endcovered #1}}{\mbox{#1}}}
通过使用\alt
和\mbox
而不是使用\only
和\makebox[0pt][r]
,我们可以避免过度打印文本#1
。
但此命令与的交互效果不佳\color
,如以下示例所示:
\documentclass{beamer}
\setbeamercovered{again covered={\opaqueness<1->{25}}}
\makeatletter
\newcommand<>{\alexurbauncover}[1]{%
#1\only#2{\makebox[0pt][r]{\beamer@endcovered #1}}}
\newcommand<>{\myuncover}[1]{%
\alt#2{\mbox{\beamer@endcovered #1}}{\mbox{#1}}}
\makeatother
\begin{document}
\begin{frame}{Frame Title}
\begin{itemize}[<+>]
\item Who's on {\color{structure} first}
\item \myuncover<.->{What}'s on {\color{structure} second}
\item \alexurbauncover<.->{I don't know}'s on {\color{structure} third}
\end{itemize}
\uncover<+>{-- Abbott and Costello}
\end{frame}
\end{document}
第一个项目符号显示了普通的\uncover
重新覆盖,这使得structure
彩色文本在重新覆盖时变得适当透明。第二个项目符号显示修订后的\myuncover
命令以某种方式破坏了彩色文本的这种处理structure
:它在重新覆盖时保持完全不透明。第三个项目符号显示这种行为不是我在修改@alexurba 的原始版本时无意中引入的\myuncover
。
因此,我修改后的问题是:我怎样才能得到类似上述内容\myuncover
并正确尊重\color
重新覆盖文本中的切换?
尝试的解决方案
据我所知,在上面的 中\myuncover
,\mbox
似乎起到了划定 的范围的作用\beamer@endcovered
。另一种想法是结束然后重新启动覆盖行为,例如使用
\newcommand<>{\myuncover}[1]{%
\alt#2{\beamer@endcovered #1\beamer@startcovered}{#1}}
但是,这个命令并不像我希望的那样工作:
\documentclass{beamer}
\setbeamercovered{again covered={\opaqueness<1->{25}}}
\makeatletter
\newcommand<>{\myuncover}[1]{%
\alt#2{\beamer@endcovered #1\beamer@startcovered}{#1}}
\makeatother
\begin{document}
\begin{frame}{Frame Title}
\begin{itemize}[<+>]
\item \myuncover<.->{Who}'s on {\color{structure} first}
\item \myuncover<.->{What}'s on {\color{structure} second}
\item \myuncover<.->{I don't know}'s on {\color{structure} third}
\end{itemize}
\uncover<+>{-- Abbott and Costello}
\end{frame}
\end{document}
我猜是\beamer@startcovered
阻止了 Beamer 识别's on first
正在被重新覆盖的等,因此again covered
无法在正确的时间点启动。但这只是猜测,因为我不了解具体\beamer@startcovered
工作原理。
答案1
编辑5
根据 OP 的建议,另一种解决方案是中断覆盖并重新启动它(与本地揭露文本相反)。这可以通过以下宏来完成:
\newcommand<>{\myinterruptcover}[1]{%
\expandafter\ifx%
\csname beamer@doafter\the\beamer@coveringdepth\endcsname\relax
#1%
\else
\alt#2{\beamer@endcovered #1\beamer@startcovered}{#1}%
\fi
}
条件检查我们当前是否处于覆盖区域,即是否\beamer@doafter<N>
(见下文)被定义。
我仍然更喜欢\myuncover
宏,因为它只是局部撤消覆盖物的颜色变化。
编辑4
@Henry DeYoung 要求我解释一下如何想出这个宏。我在下面添加了一个相当长的解释。
编辑3
在对光束源进行进一步挖掘之后,我得出了以下结论,它还保留了结构颜色(通过使用局部颜色定义):
\documentclass{beamer}
\makeatletter
\newcommand{\my@endcovered}{%
% check if \beamer@doafterN is different from \relax
% where N is the current covering level
\expandafter\ifx%
\csname beamer@doafter\the\beamer@coveringdepth\endcsname\relax
\else
% reset the color hook, but only locally
% -- in the 'real' \beamer@doafter the global \xdef is used
% instead of \edef
\edef\beamer@colorhook{%
\csname beamer@oldcolorhook\the\beamer@coveringdepth\endcsname}%
% I think the following is not needed here, though I don't really
% know what effect it has
% \edef\beamer@pgfextension{%
% \csname beamer@oldpgfextension\the\beamer@coveringdepth\endcsname}%
% finally, set colors
\color{.}%
\fi%
}%
\newcommand<>{\myuncover}[1]{\alt#2{{\my@endcovered #1}}{#1}}
\makeatother
\setbeamercovered{again covered={\opaqueness<1->{25}}}
\begin{document}
\begin{frame}{Frame Title}
\begin{itemize}[<+>]
\item \myuncover<.->{Who}'s on {\color{structure} first}
\item \myuncover<.->{What}'s on {\color{structure} second}
\item \myuncover<.->{I don't know}'s on {\color{structure} third}
\end{itemize}
\uncover<+>{-- Abbott and Costello}
\end{frame}
\end{document}
我认为这可以解决所有问题。
解释
beamer 命令\uncover
(与所有与叠加特征相关的命令一样)定义beamerbaseoverlay.sty
为
\newcommand{\uncover}{\alt{\beamer@fakeinvisible}{\beamer@makecovered}}
因此\beamer@makecovered
当覆盖规范匹配时会触发该宏。该宏又定义在与
\long\def\beamer@makecovered#1{\beamer@startcovered#1\beamer@endcovered}
这就是为什么我首先建议在局部使用\beamer@endcovered
来结束覆盖。但是,\beamer@endcovered
有一些不理想的全局影响,因此有必要更深入一点。查看宏定义
\def\beamer@endcovered{%
\beamer@smuggle{%
\csname beamer@doafter\the\beamer@coveringdepth\endcsname%
\global\advance\beamer@coveringdepth by -1\relax%
}%
}%
我们看到\beamer@endcovered
基本上扩展为\beamer@doafter<N>
,其中<N>
是计数器的当前值\beamer@coveringdepth
,它跟踪覆盖级别。最后,该计数器减少 1。正如来源中的评论所说,\beamer@smuggle
用于“偷运跳过”,我决定暂时忽略这一点(如果有人读到这篇文章并知道更多,请纠正我)。
现在它变得有点复杂了:每个\beamer@doafter<N>
都有一个对应的\beamer@do
。两个宏都定义为\beamer@actions
\def\beamer@actions#1#2{%
\gdef\beamer@do{#1%
\expandafter\gdef\csname beamer@doafter%
\the\beamer@coveringdepth\endcsname{#2}}}
在 中执行\beamer@startcovered
。如您所见,实际上doafter
宏是在do
展开时定义的。来自 的相关代码片段\beamer@starcovered
位于 的定义中\opaqueness
:
\def\opaqueness<##1>##2{%
\only<##1>{%
\beamer@actions{%
\expandafter\xdef\csname beamer@oldcolorhook%
\the\beamer@coveringdepth\endcsname{\beamer@colorhook}%
\expandafter\xdef\csname beamer@oldpgfextension%
\the\beamer@coveringdepth\endcsname{\beamer@pgfextension}%
{\globalcolorstrue\colorlet{beamer@freeze\the\beamer@coveringdepth}{bg}}%
\xdef\beamer@colorhook{!##2!beamer@freeze%
\the\beamer@coveringdepth\beamer@colorhook}%
\gdef\beamer@pgfextension{!##2opaque}%
\color{.}%
}%
{%
\xdef\beamer@colorhook{\csname beamer@oldcolorhook%
\the\beamer@coveringdepth\endcsname}%
\xdef\beamer@pgfextension{\csname beamer@oldpgfextension%
\the\beamer@coveringdepth\endcsname}%
\color{.}%
}}}%
这里,\beamer@actions
如果覆盖规范匹配,则调用。然后将宏\beamer@do
和\beamer@doafter<N>
设置为参数。现在很明显,宏\beamer@do
负责设置覆盖对象的颜色(这取决于用户设置)。先前的颜色钩子保存到名为的宏中\beamer@oldcolorhook<N>
,其中<N>
再次是覆盖级别。当\beamer@doafter
展开时,将准确恢复此颜色钩子:
\xdef\beamer@colorhook{\csname beamer@oldcolorhook%
\the\beamer@coveringdepth\endcsname}%
\xdef\beamer@pgfextension{\csname beamer@oldpgfextension%
\the\beamer@coveringdepth\endcsname}%
\color{.}%
这些就是我们想要的代码行。我只是 \xdef
用局部代码替换了全局代码\gdef
,以限制颜色重新定义的范围。
最后只缺少一点:如上所述,只有当中的\beamer@doafter
覆盖规范(的\only
)\opaqueness
匹配时,的定义才为真。如果不是这种情况,则宏不会执行任何操作,并且等于\relax
。所以我的宏检查是否\beamer@doafter
等于,\relax
在这种情况下它也不会执行任何操作。
编辑2
现在这应该真正产生期望的结果:
\documentclass{beamer}
\setbeamercovered{again covered={\opaqueness<1->{25}}}
\makeatletter
\newcommand*{\myuncover}[1]{%
#1\only<.->{\makebox[0pt][r]{\beamer@endcovered #1}}%
}
\makeatother
\begin{document}
\begin{frame}{Frame Title}
\begin{itemize}[<+>]
\item \myuncover{Who}'s on first
\item \myuncover{What}'s on second
\item \myuncover{I don't know}'s on third
\end{itemize}
\uncover<+>{-- Abbott and Costello}
\end{frame}
\end{document}