670 likes | 965 Views
윈도우 8.1 앱개발 새로운 API 들. 이길복 / 주신영. Speakers. 주신영 MVP 스마트쉐어 CEO. 이길복 MVP 휴즈플로우 CTO. Windows 8.1: Free for all Windows 8 PCs. 1. Controls. TextBlock. < TextBlock Text="First line is using the defaults" /> < TextBlock Text="Second line"
E N D
윈도우 8.1 앱개발 새로운 API들 이길복 / 주신영
Speakers 주신영 MVP 스마트쉐어CEO 이길복MVP 휴즈플로우CTO
1 Controls
TextBlock <TextBlockText="First line is using the defaults" /> <TextBlockText="Second line" FontSize="40" FontWeight="Bold" FontStyle="Italic" FontFamily="Times New Roman"/> <TextBlockText="I will not be able to finish this sentence." FontSize="30" HorizontalAlignment="Left" TextTrimming="WordEllipsis" Width="450" /> <TextBlockText="1/4, 1/2, 1/3, 3263827/8675309" FontSize="40" TextAlignment="Right" Typography.Fraction="Slashed"/> <TextBlockText="Microsoft Windows" FontSize="60" FontFamily="Gabriola" Foreground="Aqua" Typography.StylisticSet4="True"/> <TextBlockText="Microsoft Windows" FontSize="60" FontFamily="Gabriola" Typography.StylisticSet5="True"/> <TextBlockText="Microsoft Windows" FontSize="60" FontFamily="Gabriola" Foreground="LightGreen" Typography.StylisticSet6="True"/> <TextBlockText="Microsoft Windows" FontSize="60" Foreground="#FFAA00FF" FontFamily="Gabriola" Typography.StylisticSet7="True"/>
RichTextBlock <RichTextBlockOverflowContentTarget="{Binding ElementName=SecondColumnOverflow}" FontSize="25" Grid.Column="0" Margin="5"> <ParagraphTextAlignment="Justify" Margin="5"> This is justified text. Loremipsum dolor sit amet, consectetur … </Paragraph> <Paragraph> <HyperlinkNavigateUri="http://microsoft.com" FontSize="25">Link to Microsoft Main Site</Hyperlink> </Paragraph> <ParagraphTextAlignment="Right" Margin="5"> This is right-justified text. Integer hendreritdiam vitae …. <InlineUIContainer> <Button Content="Button" Width="120" Height="40" /> </InlineUIContainer> <Run Foreground="LightBlue"> And so is this. Class aptenttacitisociosqu ad … </Run> </Paragraph> <ParagraphTextAlignment="Center" Margin="5"> This is centered text. Duisvel semper augue... <Run Text="This is some text in its own run, using its own text style" FontStyle="Italic" Foreground="Orange"/> This is also centered. In commodoeros … </Paragraph> </RichTextBlock> <RichTextBlockOverflowx:Name="SecondColumnOverflow"Grid.Column="1" Margin="5"/>
TextBox and PasswordBox <TextBoxText="Hello world" /> <TextBoxText="Headers can be templated" Header="TextBox Header Text"/> <TextBoxText="I am going to the store for moar bread." Header="Spell-checking" IsSpellCheckEnabled="True"/> <TextBoxHeader="Placeholder text" PlaceholderText="please enter your first name"/> <TextBoxHeader="Color Font Support" Text="I like tapioca. 😀" IsColorFontEnabled="True" FontFamily="Segoe UI Emoji" /> <TextBoxText="For on-screen keyboards only" Header="Text Prediction" IsTextPredictionEnabled="True"/> <TextBoxText="pete@contoso.com" Header="Input scope control" PlaceholderText="For touch keyboard" InputScope="EmailSmtpAddress"/> <TextBoxText="Peter piper picked a peck" Header="Selection highlight color control" SelectionHighlightColor="Orange"/> <PasswordBoxHeader="Please enter your password" FontSize="40" Margin="20" IsPasswordRevealButtonEnabled="True" Password="Password1" />
<TextBoxInputScope="EmailSmtpAddress"/> Input scope 키보드 레이아웃 결정. 데이터 검증까지 제공하진 않음. 좋은 UX에 도움되는 것은 알지만, 설정하는 것을 잊기 쉬운데…타블렛과 터치스크린 사용자들을 위해서 꼭 신경써줘야 할 것. <TextBoxInputScope="Formula"/> <TextBoxInputScope="Number"/>
DatePicker and TimePicker <DatePickerHeader="Gregorian Calendar Identifier" CalendarIdentifier="GregorianCalendar" DayFormat="{}{day.integer} {dayofweek.full}" /> <DatePickerHeader="Korean Calendar Identifier" CalendarIdentifier="KoreanCalendar" DayFormat="{}{day.integer} {dayofweek.full}" /> <DatePickerHeader="Julian Calendar Identifier" CalendarIdentifier="JulianCalendar" DayFormat="{}{day.integer} {dayofweek.full}" /> <DatePickerHeader="Day of week without day" DayFormat="{}{dayofweek.solo.full}"/> <DatePickerHeader="Day of week abbreviated" DayFormat="{}{day.integer} {dayofweek.abbreviated}"/> <TimePickerHeader="Time Picker with 12 hour clock" ClockIdentifier="12HourClock"/> <TimePickerHeader="Time Picker with 24 hour clock" ClockIdentifier="24HourClock"/> DatePicker TimePicker
Flyouts <Button Content="Show Normal Flyout" Margin="100, 20, 100, 20"> <Button.Flyout> <Flyout> <StackPanelWidth="250"> <TextBlockText="Some header text" FontSize="24" Margin="0,0,0,20" FontWeight="Light" Foreground="CornflowerBlue"/> <TextBlockText="This type of flyout is a ..." FontSize="16" TextWrapping="Wrap" /> <Button Content="Do Something" HorizontalAlignment="Right" Margin="0,20,0,0"/> </StackPanel> </Flyout> </Button.Flyout> </Button> <Button Content="Show Menu Flyout" Margin="20, 20, 100, 20"> <Button.Flyout> <MenuFlyout> <MenuFlyoutItemText="Option 1" /> <MenuFlyoutItemText="Option 2" /> <MenuFlyoutSeparator/> <ToggleMenuFlyoutItemText="Toggle Option 1" IsChecked="True" /> <ToggleMenuFlyoutItemText="Toggle Option 2" /> </MenuFlyout> </Button.Flyout> </Button>
Image <TextBlockText="UI Resize" FontSize="30" /> <Image Source="ms-appx:///Assets/Images/Pro2.png" Width="400"/> <TextBlockText="Decode Resize" FontSize="30" /> <Image Width="400"> <Image.Source> <BitmapImageDecodePixelWidth="600" UriSource="ms-appx:///Assets/Images/Pro2.png" /> </Image.Source> </Image> DecodePixelWidth/Height 불러올 때 크기를 제공하면 메모리를 절약할 수 있다. 퍼포먼스도 좋아진다. 확대/축소된 결과도 더 품질이 좋다.
2 ItemsControls and lists
Data template Data Chinese French German Indian Italian Mexican
ListView <ListViewx:Name="ItemListView" Height="325" HorizontalAlignment="Left" ItemTemplate="{StaticResourceStoreFrontTileTemplate}" ItemContainerStyle="{StaticResourceContainerStyle}" ShowsScrollingPlaceholders="False" BorderBrush="LightGray" BorderThickness="1" SelectionMode="None"/>
GridView <GridViewx:Name="ItemGridView2" ItemTemplate="{StaticResourceStoreFrontTileTemplate}" ItemContainerStyle="{StaticResourceStoreFrontTileStyle}" ItemsPanel="{StaticResourceStoreFrontGridItemsPanelTemplate}" ShowsScrollingPlaceholders="False" BorderBrush="LightGray" BorderThickness="1" />
FlipView <FlipViewx:Name="FlipView1" Width="480" Height="270" BorderBrush="Black" BorderThickness="1"> <FlipView.ItemTemplate> <DataTemplate> <Grid> <Image Width="480" Height="270" Source="{Binding Image}" Stretch="UniformToFill"/> <Border Background="#A5000000" Height="80" VerticalAlignment="Bottom"> <TextBlockText="{Binding Title}" FontFamily="Segoe UI" FontSize="26.667" Foreground="#CCFFFFFF" Padding="15,20"/> </Border> </Grid> </DataTemplate> </FlipView.ItemTemplate> </FlipView> Data Template DataContext for binding is the item being rendered
가상화 불가 가상화 가능 새 가상화는 기본으로 활성화 되어있음. ItemsStackPanel과ItemsWrapGrid 가변사이즈 아이템을 지원할 때는 가상화 불가. 같은 크기에, 같은 템플릿을 사용하는 경우에만 가상화 작동. VariableSizedWrapGrid는 가상화 불가 가상화 불가
Large list performance <GridViewItemPresenter SelectionCheckMarkVisualEnabled="False" SelectedBackground="#FFFF8c00" SelectedBorderThickness="5" /> = + 퍼포먼스 개선 불필요한 엘리먼트의 생성을 줄이기.GridViewItemPresenter의 사용.
Placeholders로가시적인 퍼포먼스 개선 • <GridViewShowsScrollingPlaceholders="true">
Incrementally updating the data template GridView의 ContainerContentChanging이벤트
3 Windowing and Layout
Windows 8 view states Full landscape Full portrait Filled Snapped
Windows in Windows 8.1 Wider than tall window Taller than wide window Taller than wide window Taller than wide window
Windows 8.1 접근 앱은 최소 500px 폭을 지원해야함. 세로로 긴 레이아웃을 지원할 것. 320px에서 499px는선택적으로 지원 Page 기초 클래스나 View State를 더 이상 지원 안 함. 이제 좋은 툴킷을 맘대로 쓰고 개발자 마음대로 하세용 동시에 두 개 이상의 앱을 지원 대형화면은 앱을 다섯 개까지! 보통은 두, 세 가지.
App-specific visual states <VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualStatex:Name="PrimaryLayout"> <Storyboard> ... </Storyboard> </VisualState> <VisualStatex:Name="NarrowLayout"> <Storyboard> ... </Storyboard> </VisualState> <VisualStatex:Name="TallLayout"> <Storyboard> ... </Storyboard> </VisualState> <VisualStatex:Name="ExtraLargeLayout"> <Storyboard> ... </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> Visual States Visual states는 UI와 코드를 분리해 주죠. 코드에서 수동으로 엘리먼트 이동하고, 크기변경하고 하는 대신에 간단히 이 변경사항들을 처리하는 Storyboard를 가진 visual state로 변경하는 게 깔끔하죠.
Setting visual states from code voidOnWindowSizeChanged(object sender, WindowSizeChangedEventArgs e) { if (e.Size.Width < _minPrimaryWidth) VisualStateManager.GoToState(this, _narrowVS, true); else if (e.Size.Width < e.Size.Height) VisualStateManager.GoToState(this, _tallVS, true); else if (e.Size.Width > _maxPrimaryWidth && e.Size.Width > _maxPrimaryWidth) VisualStateManager.GoToState(this, _xlVS, true); else VisualStateManager.GoToState(this, _primaryVS, true); } const string _primaryVS = "PrimaryLayout"; const string _narrowVS = "NarrowLayout"; const string _tallVS = "TallLayout"; const string _xlVS = "ExtraLargeLayout"; const double _minPrimaryWidth = 500.0; const double _maxPrimaryWidth = 1920.0; const double _maxPrimaryHeight = 1080.0; Use constants Sizes and state names will almost certainly change during design iterations
방향과 위치 Orientation ApplicationView.Orientation (Landscape 또는 Portrait을 반환) Placement ApplicationView.AdjacentToLeftDisplayEdge ApplicationView.AdjacentToRightDisplayEdge Full Screen ApplicationView.IsFullScreen
Window 크기 페이지 불러올 때 창크기 Window.Current.Bounds: 초기 크기 런타임 사이즈는 Window.SizeChanged이벤트 핸들러에서 페이지가 사라질 때는 핸들러를 끊어주는 센스! Window 크기와 실제 화면 사이즈와는 아무 관계 없음! 전체화면일 때조차도 픽셀은 논리적 픽셀수.
Handling the SizeChanged event protected override void OnNavigatedTo(NavigationEventArgs e) { navigationHelper.OnNavigatedTo(e); Window.Current.SizeChanged += OnWindowSizeChanged; } protected override void OnNavigatedFrom(NavigationEventArgs e) { navigationHelper.OnNavigatedFrom(e); Window.Current.SizeChanged -= OnWindowSizeChanged; } 핸들러 제거하는 것 잊지 마세요! 팁: 모든 닷넷 프로그램에서 메모리 누수가 발생하는 흔한 원인 중 하나가 제대로 이벤트 핸들러를 제거하지 않는 것이다. 싱글턴 객체나 정적 클래스의 이벤트에 대한 핸들러는 꼭 제거합시다.
Show a secondary view ViewSizePreference Default 기본값은 UseHalf와 같은 절반. UseMore 가로 50% 이상을 차지 UseHalf 절반 UseLess 가로 50% 이하를 차지 UseMinimum Manifest에 정해 놓은 최소값인 320 또는 500 픽셀 UseNone 보여주지 않음 Create varview = CoreApplication.CreateNewView(); varviewId = 0; awaitview.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { viewId = ApplicationView.GetForCurrentView().Id; varwindow = Window.Current; varframe = new Frame(); window.Content = frame; frame.Navigate(typeof(SecondaryWindowContentPage)); }); awaitApplicationViewSwitcher.TryShowAsStandaloneAsync(viewId, ViewSizePreference.UseHalf, ApplicationView.GetForCurrentView().Id, ViewSizePreference.UseHalf); Setup window content Show
4 Speech Synthesis
Speech synthesis • Voice • David(en-US, 남성) • Zira(en-US, 여성) • Hazel(en-UK, 여성) • Heami(ko-KR, 여성) • 외 13개국 음성 지원
Speech synthesis Code • 단순 텍스트 음성 출력 • synthesizeTextToStreamAsync • PC의 위치 설정에 따라 음성 지원 var synth = newWindows.Media.SpeechSynthesis.SpeechSynthesizer(); SpeechSynthesisStream stream = awaitsynth.SynthesizeTextToStreamAsync("Welcome!"); media.SetSource(stream, stream.ContentType); media.Play();
Speech synthesis Code • SSML(Speech Synthesis Markup Language) • synthesizeSsmlToStreamAsync • 음성 특징, 발음, 볼륨, 피치, 비율 / 속도, 강도 stringSsml = @"<speak version='1.0' " + "xmlns='http://www.w3.org/2001/10/synthesis' xml:lang='en-US'>" + "<prosody contour='(0%,+80Hz) (10%,+80%) (40%,+80Hz)'>Welcome! Shinyoung" + "<break time='500ms' />" + "Have a good time" + "</prosody></speak>"; var synth = newWindows.Media.SpeechSynthesis.SpeechSynthesizer(); SpeechSynthesisStream stream = awaitsynth.SynthesizeSsmlToStreamAsync(Ssml); media.SetSource(stream, stream.ContentType); media.Play();
5 Contact &Appointment
Contact • People 앱을 통한 연락처 관리 • 이메일 및 소셜 계정의 연락처 연동됨 • 모든 연락처의 추가/수정/ 삭제 • ContactPickerUI를통한 연락처들 호출 • ContactManager.ShowContactCard()를 통해 바로 원하는 연락처의 ContactCard를 호출 • 대부분의 사용자는개인정보 유출에 대한 우려로 앱 자체에서 연락처정보의 관리/보호/저장 하는 것을 원하지 않음.
Contact Picker • Appxmanifest에서 Contact Picker 사용 선언
Contact Picker Code ContactPickerpicker = new ContactPicker(); picker.SelectionMode= ContactSelectionMode.Contacts; // Contact contacts = await picker.PickContactAsync(); // 1개 IList<Contact> contacts = await picker.PickContactsAsync(); // 여러개 foreach (Contact contactin contacts) { // process each contact returned Debug.WriteLine(contact.FirstName+ " " + contact.LastName); } ContactPickerUI로 UI를 커스텀 가능
Contact card Contact card workflow Source App Target App Action + Object Windows Runtime From: Ben Miller View Profile ContactManager Windows Contact Store
ContactManager Code Contactcontact = newContact(); contact.FirstName= "주"; contact.LastName= "신영"; ContactEmailemail = newContactEmail(); email.Address= “bit1010@live.com"; contact.Emails.Add(email); Rectrect = Helper.GetElementRect(sender asFrameworkElement); ContactManager.ShowContactCard(contact, rect, Windows.UI.Popups.Placement.Default);
Appointments • Calrendar앱을 통한 일정 관리 • 이메일 및 소셜 계정의 일정 연동됨 • 모든 일정의 추가/수정/ 삭제 • AppointmentManager. ShowAddAppointmentAsync(…)를 통해 바로 원하는 일정 ContactCard를 호출
Appointments Source App Target App Action + Object Windows Runtime AppointmentManager. ShowAddAppointmentAsync(…) Windows Appointment Store
Appointments Code • private async void AddAppointment_Click(object sender, RoutedEventArgs e) • { • var appointment = new Appointment(); • appointment.Subject = "Prepare for next session"; • appointment.StartTime = DateTime.Now.AddMinutes(2); • appointment.Duration = TimeSpan.FromHours(1); • appointment.Location = "Speaker room"; • appointment.Uri = new Uri("http://dev.windows.com"); • appointment.Sensitivity = AppointmentSensitivity.Public; • appointment.Details = "Nothing like a little procrastination!";
Appointments Code Rectrect = Helper.GetElementRect(sender as FrameworkElement); varid = awaitAppointmentManager.ShowAddAppointmentAsync( appointment, rect, Windows.UI.Popups.Placement.Above); if(!string.IsNullOrEmpty(id)) ResultDisplay.Text = "Returned appointment id " + id; else ResultDisplay.Text = "Appointment not added."; } }
Contact &Appointment demo
6 Bluetooth
Bluetooth in Windows 8.1 Windows 8.1 PC running your Windows Store app Windows.Devices.Bluetooth.Rfcomm Windows.Devices.Bluetooth.GenericAttributeProfile