Enquadrar e detalhar juntos

Enquadrar e detalhar juntos

Eu quero redefinir framecomo frame + itemize. Eu até agora tentei isso -

\documentclass{beamer}
\newenvironment{myframe}{\begin{frame}\begin{itemize}}{\end{itemize}\end{frame}}

\begin{document}
\begin{myframe}
\item
\end{myframe}
\end{document}

O que exatamente há de errado nisso e como redefinir isso corretamente?

Responder1

O beamerambiente framecoleta seu corpo usando a seguinte técnica: ele lê e armazena tokens seguindo \begin{frame}a busca \end{frame}sem expandi-los exceto em um caso (veja abaixo), mas aceitará an \end{frame}como final do corpo do ambiente sendo coletado somente se tiver visto o mesmo número que \begin{...}durante \end{...}este processo de coleta (não tenta combiná-los). É \beamer@begin@stackpara isso que é usado \beamer@collect@@bodyfrom beamerbaseframe.sty.

Caso a pilha esteja vazia (ou seja, tenha visto tantas \end{...}quanto \begin{...}depois de \begin{frame}) e o seguinte \end{...}não seja um \end{frame}, ele expande isso \endesperando que isso faça \end{frame}aparecer. 1 Mas issoapenasacontece sob a condição que dei (tantas \end{...}depois \begin{...}da inicial \begin{frame}devem ter sido vistas).

No seu exemplo, \begin{itemize}empurra um b(ou seja, abre um nível) para a \beamer@begin@stackpilha. Isso baparece quando \end{myframe}é lido. Neste ponto, \beamer@collect@@bodysabe que já viu tantos \begin{...}como \end{...}depois do \begin{frame}. Isto é verdade, mas enganoso, pois se \end{myframe}fosse expandido, produziria dois pops. Então, \beamer@begin@stackpensa que o próximo \end{...}deve fornecer \end{frame}, possivelmente após expandir o \end...token (ver nota de rodapé 1). Infelizmente, isso está incorreto; o próximo \end{...}é \end{document}. \enddocumenté assim expandido, \beamer@collect@@bodycontinua procurando, \end{frame}mas é claro que nunca o encontra, chega ao final do arquivo, o que aciona o erro:

Runaway argument?
\let \AtEndDocument \@firstofone \@enddocumenthook \@checkend {docume\ETC.
! File ended while scanning use of \beamer@collect@@body.
<inserted text> 
                \par 

Então, basicamente, o problema é que \beamer@collect@@bodynão é possível manter uma contagem adequada de \end{...}porque você \end{myframe}esconde dois desses ( \end{itemize}\end{frame}) e \beamer@collect@@bodynão os descobrirá por meio da expansão de \endmyframeapesar da presença de \end{myframe}, porque viu mais \begin{...}do que \end{...}no ponto em que vê this \end{myframe}(pilha não vazia devido ao \begin{itemize}).

As soluções exigem que você não se esconda \end{...}em macros que \beamer@collect@@bodynão vão se expandir. Um está usando o environpacote como emresposta de ferahfeza, outro está usando \itemizee \enditemizeda seguinte maneira (nenhum deles afeta a \beamer@begin@stackpilha, portanto, quando \beamer@collect@@body\end{myframe}, a pilha está vazia, portanto \endmyframeé expandida uma vez, o que torna o \end{frame}processo de digitalização do corpo visível para o ambiente):

\documentclass{beamer}

\newenvironment*{myframe}[1]
  {\begin{frame}{#1}%
   \begingroup\itemize}
  {\enditemize\endgroup
   \end{frame}}

\begin{document}

\begin{myframe}{Frame title}
\item An item
\item Another item
\end{myframe}

\end{document}

Captura de tela


Nota de rodapé

  1. Mais precisamente, o que acontece é o seguinte (in beamer 2018/12/02 v3.55). Se:

    • a \beamer@begin@stackpilha está vazia (tantas quantas \end{...}foram \begin{...}vistas após \begin{frame}cujo corpo está sendo coletado) e
    • o próximo \end{...}não é um \end{frame}- digamos que é um \end{foobar},

    em seguida \beamer@collect@@body, substitui a expansão de primeiro nível \endfoobar\endgrouppor isso \end{foobar}no material coletado. Isto é semelhante ao que a expansão \end{foobar}produziria, embora esta última fizesse mais algumas coisas (ver source2e.pdfp. 272):

    • verifique se o texto de substituição de \@currenviris foobar(isso falharia no beamer frameprocesso de coleta do corpo de que estamos falando, as \@currenviris frame);
    • respeitar um comando anterior \@endparenv(usado para suprimir o recuo do parágrafo no início do texto após alguns ambientes de criação de parágrafos, a menos que o referido texto seja precedido por uma linha em branco ou por \par);
    • honrar um \ignorespacesafterendcomando anterior (usado para fazer o próximo \end{...}ignorar os espaços que possam segui-lo).

Responder2

Usando pacote environ:

\documentclass{beamer}
\usepackage{environ}

\NewEnviron{myframe}[1][]{%
\begin{frame}{#1}
\begin{itemize}
\BODY
\end{itemize}
\end{frame}
}

\begin{document}
\begin{myframe}
\item First
\item Second
\end{myframe}
\end{document}

insira a descrição da imagem aqui

informação relacionada