diff --git a/Pixiview.iOS/Pixiview.iOS.csproj b/Pixiview.iOS/Pixiview.iOS.csproj
index 61894a4..8b5ff94 100644
--- a/Pixiview.iOS/Pixiview.iOS.csproj
+++ b/Pixiview.iOS/Pixiview.iOS.csproj
@@ -78,6 +78,7 @@
     <Compile Include="Services\FileStore.cs" />
     <Compile Include="Renderers\AppShellRenderer.cs" />
     <Compile Include="Renderers\AppShellSection\AppShellSectionRootHeader.cs" />
+    <Compile Include="Renderers\SegmentedControlRenderer.cs" />
   </ItemGroup>
   <ItemGroup>
     <InterfaceDefinition Include="Resources\LaunchScreen.storyboard" />
diff --git a/Pixiview.iOS/Renderers/AppShellRenderer.cs b/Pixiview.iOS/Renderers/AppShellRenderer.cs
index ee384fc..904a200 100644
--- a/Pixiview.iOS/Renderers/AppShellRenderer.cs
+++ b/Pixiview.iOS/Renderers/AppShellRenderer.cs
@@ -35,7 +35,7 @@ namespace Pixiview.iOS.Renderers
                 if (renderer.ViewController is UITabBarController controller)
                 {
                     var tabBar = controller.TabBar;
-                    tabBar.TintColor = UIColor.SecondaryLabelColor.ColorWithAlpha(1);
+                    tabBar.TintColor = UIColor.LabelColor;
                     tabBar.UnselectedItemTintColor = UIColor.SecondaryLabelColor;
                 }
             }
diff --git a/Pixiview.iOS/Renderers/SegmentedControlRenderer.cs b/Pixiview.iOS/Renderers/SegmentedControlRenderer.cs
new file mode 100644
index 0000000..c56a1ca
--- /dev/null
+++ b/Pixiview.iOS/Renderers/SegmentedControlRenderer.cs
@@ -0,0 +1,155 @@
+using System;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+using Pixiview.iOS.Renderers;
+using Pixiview.UI;
+using UIKit;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.iOS;
+
+[assembly: ExportRenderer(typeof(SegmentedControl), typeof(SegmentedControlRenderer))]
+namespace Pixiview.iOS.Renderers
+{
+    [SuppressMessage("Code Notifications", "XI0002:Notifies you from using newer Apple APIs when targeting an older OS version", Justification = "<Pending>")]
+    public class SegmentedControlRenderer : ViewRenderer<SegmentedControl, UISegmentedControl>
+    {
+        private UISegmentedControl nativeControl;
+
+        protected override void OnElementChanged(ElementChangedEventArgs<SegmentedControl> e)
+        {
+            base.OnElementChanged(e);
+
+            var element = Element;
+            if (Control == null && element != null)
+            {
+                nativeControl = new UISegmentedControl();
+
+                for (var i = 0; i < element.Children.Count; i++)
+                {
+                    nativeControl.InsertSegment(element.Children[i].Text, i, false);
+                }
+
+                nativeControl.Enabled = element.IsEnabled;
+                nativeControl.BackgroundColor = element.BackgroundColor.ToUIColor();
+                nativeControl.SelectedSegmentTintColor = GetTintColor(element);
+                SetTextColor();
+                nativeControl.SelectedSegment = element.SelectedSegmentIndex;
+
+                SetNativeControl(nativeControl);
+            }
+
+            if (e.OldElement != null)
+            {
+                if (nativeControl != null)
+                {
+                    nativeControl.ValueChanged -= NativeControl_ValueChanged;
+                }
+            }
+
+            if (e.NewElement != null)
+            {
+                nativeControl.ValueChanged += NativeControl_ValueChanged;
+            }
+        }
+
+        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+        {
+            base.OnElementPropertyChanged(sender, e);
+
+            var element = Element;
+            if (nativeControl == null || element == null)
+            {
+                return;
+            }
+
+            switch (e.PropertyName)
+            {
+                case "Renderer":
+                    element.SendValueChanged();
+                    break;
+
+                case nameof(element.BackgroundColor):
+                    nativeControl.BackgroundColor = element.BackgroundColor.ToUIColor();
+                    break;
+
+                case nameof(element.SelectedSegmentIndex):
+                    nativeControl.SelectedSegment = element.SelectedSegmentIndex;
+                    break;
+
+                case nameof(element.TintColor):
+                    nativeControl.SelectedSegmentTintColor = GetTintColor(element);
+                    break;
+
+                case nameof(element.IsEnabled):
+                    nativeControl.Enabled = element.IsEnabled;
+                    nativeControl.SelectedSegmentTintColor = GetTintColor(element);
+                    break;
+
+                case nameof(element.SelectedTextColor):
+                    SetTextColor();
+                    break;
+            }
+        }
+
+        private void SetTextColor()
+        {
+            var color = Element.SelectedTextColor;
+            UIColor c = color == default ? UIColor.LabelColor : color.ToUIColor();
+            var attribute = new UITextAttributes
+            {
+                TextColor = c
+            };
+            nativeControl.SetTitleTextAttributes(attribute, UIControlState.Selected);
+            attribute = new UITextAttributes
+            {
+                TextColor = c.ColorWithAlpha(.6f)
+            };
+            nativeControl.SetTitleTextAttributes(attribute, UIControlState.Normal);
+        }
+
+        private UIColor GetTintColor(SegmentedControl element)
+        {
+            if (element.IsEnabled)
+            {
+                var tintColor = element.TintColor;
+                if (tintColor == default)
+                {
+                    return UIColor.QuaternaryLabelColor;
+                }
+                else
+                {
+                    return tintColor.ToUIColor().ColorWithAlpha(.3f);
+                }
+            }
+            else
+            {
+                var disabledColor = element.DisabledColor;
+                if (disabledColor == default)
+                {
+                    return UIColor.SecondaryLabelColor;
+                }
+                else
+                {
+                    return disabledColor.ToUIColor();
+                }
+            }
+        }
+
+        private void NativeControl_ValueChanged(object sender, EventArgs e)
+        {
+            Element.SelectedSegmentIndex = (int)nativeControl.SelectedSegment;
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (nativeControl != null)
+            {
+                nativeControl.ValueChanged -= NativeControl_ValueChanged;
+                nativeControl.Dispose();
+                nativeControl = null;
+            }
+
+            base.Dispose(disposing);
+        }
+    }
+}
diff --git a/Pixiview/AppShell.xaml b/Pixiview/AppShell.xaml
index a59005e..e686802 100644
--- a/Pixiview/AppShell.xaml
+++ b/Pixiview/AppShell.xaml
@@ -67,18 +67,9 @@
             <ShellContent ContentTemplate="{DataTemplate i:MainPage}"/>
         </Tab>
         <Tab Icon="{DynamicResource FontIconSparkles}"
-             Title="{r:Text Recommends}">
-            <ShellContent Title="{r:Text Recommends}"
-                          ContentTemplate="{DataTemplate i:RecommendsPage}"
-                          Route="{x:Static util:Routes.Recommends}"/>
-            <ShellContent Title="{r:Text ByUser}"
-                          Route="{x:Static util:Routes.ByUser}">
-                <ShellContent.ContentTemplate>
-                    <DataTemplate>
-                        <i:RecommendsPage ByUser="True"/>
-                    </DataTemplate>
-                </ShellContent.ContentTemplate>
-            </ShellContent>
+             Title="{r:Text Recommends}"
+             Route="{x:Static util:Routes.Recommends}">
+            <ShellContent ContentTemplate="{DataTemplate i:RecommendsPage}"/>
         </Tab>
         <Tab Icon="{DynamicResource FontIconOrder}"
              Title="{r:Text Ranking}"
diff --git a/Pixiview/Illust/IllustCollectionPage.cs b/Pixiview/Illust/IllustCollectionPage.cs
index 41f9100..a0212ec 100644
--- a/Pixiview/Illust/IllustCollectionPage.cs
+++ b/Pixiview/Illust/IllustCollectionPage.cs
@@ -67,6 +67,8 @@ namespace Pixiview.Illust
 
         #endregion
 
+        protected Thickness totalBarOffset;
+        protected Thickness navigationBarOffset;
         protected bool loaded;
 
         private T illustData;
@@ -297,7 +299,7 @@ namespace Pixiview.Illust
 
         #region - Illust Tasks -
 
-        void DoLoadIllusts(bool force = false)
+        protected void DoLoadIllusts(bool force = false, bool skipImage = false)
         {
             illustData = DoLoadIllustData(force);
             if (illustData == null)
@@ -321,7 +323,10 @@ namespace Pixiview.Illust
             Illusts = collection;
             Loading = false;
 
-            DoLoadImages(collection);
+            if (!skipImage)
+            {
+                DoLoadImages(collection);
+            }
         }
 
         void DoLoadImages(IllustCollection collection)
diff --git a/Pixiview/Illust/RankingPage.xaml b/Pixiview/Illust/RankingPage.xaml
index 5c9369f..d3d1f4a 100644
--- a/Pixiview/Illust/RankingPage.xaml
+++ b/Pixiview/Illust/RankingPage.xaml
@@ -23,8 +23,7 @@
                    CancelButtonColor="{DynamicResource SubTextColor}"
                    Text="{Binding Keywords, Mode=TwoWay}"
                    SearchButtonPressed="SearchBar_SearchButtonPressed"
-                   Unfocused="SearchBar_Unfocused"
-                   />
+                   Unfocused="SearchBar_Unfocused"/>
         <Frame HasShadow="False" Margin="0" Padding="20" CornerRadius="8"
                IsVisible="{Binding Loading}"
                HorizontalOptions="Center" VerticalOptions="Center"
diff --git a/Pixiview/Illust/RankingPage.xaml.cs b/Pixiview/Illust/RankingPage.xaml.cs
index fb9848a..a652218 100644
--- a/Pixiview/Illust/RankingPage.xaml.cs
+++ b/Pixiview/Illust/RankingPage.xaml.cs
@@ -19,9 +19,6 @@ namespace Pixiview.Illust
             set => SetValue(KeywordsProperty, value);
         }
 
-        private readonly Thickness totalBarOffset;
-        private readonly Thickness navigationBarOffset;
-
         public RankingPage()
         {
             totalBarOffset = new Thickness(0, AppShell.TotalBarOffset.Top + 50, 0, 0);
diff --git a/Pixiview/Illust/RecommendsPage.xaml b/Pixiview/Illust/RecommendsPage.xaml
index 8993efb..ec1ee17 100644
--- a/Pixiview/Illust/RecommendsPage.xaml
+++ b/Pixiview/Illust/RecommendsPage.xaml
@@ -11,13 +11,26 @@
         <ToolbarItem Order="Primary" Clicked="Refresh_Clicked"
                      IconImageSource="{DynamicResource FontIconRefresh}"/>
     </ContentPage.ToolbarItems>
-    <Grid>
+    <Grid Padding="{Binding PageTopMargin}">
         <ScrollView HorizontalOptions="Fill">
             <u:FlowLayout ItemsSource="{Binding Illusts}"
                           HorizontalOptions="Fill" Column="{Binding Columns}"
-                          Margin="16" RowSpacing="16" ColumnSpacing="16"
+                          Margin="16, 6, 16, 16" RowSpacing="16" ColumnSpacing="16"
                           ItemTemplate="{StaticResource cardView}"/>
         </ScrollView>
+        <Grid Margin="0, -40, 0, 0" VerticalOptions="Start" HeightRequest="40">
+            <u:SegmentedControl VerticalOptions="Center" HorizontalOptions="Center"
+                                HeightRequest="30"
+                                BackgroundColor="{DynamicResource WindowColor}"
+                                TintColor="{DynamicResource SubTextColor}"
+                                SelectedTextColor="{DynamicResource TextColor}"
+                                SelectedSegmentIndex="{Binding SegmentIndex, Mode=TwoWay}">
+                <u:SegmentedControl.Children>
+                    <u:SegmentedControlOption Text="{r:Text Recommends}"/>
+                    <u:SegmentedControlOption Text="{r:Text ByUser}"/>
+                </u:SegmentedControl.Children>
+            </u:SegmentedControl>
+        </Grid>
         <Frame HasShadow="False" Margin="0" Padding="20" CornerRadius="8"
                IsVisible="{Binding Loading}"
                HorizontalOptions="Center" VerticalOptions="Center"
diff --git a/Pixiview/Illust/RecommendsPage.xaml.cs b/Pixiview/Illust/RecommendsPage.xaml.cs
index 3c2d2b2..7eca300 100644
--- a/Pixiview/Illust/RecommendsPage.xaml.cs
+++ b/Pixiview/Illust/RecommendsPage.xaml.cs
@@ -2,16 +2,36 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Windows.Input;
+using Pixiview.UI;
 using Pixiview.Utils;
+using Xamarin.Forms;
 
 namespace Pixiview.Illust
 {
     public partial class RecommendsPage : IllustDataCollectionPage
     {
-        public bool ByUser { get; set; }
+        public static readonly BindableProperty SegmentIndexProperty = BindableProperty.Create(
+            nameof(SegmentIndex), typeof(int), typeof(RecommendsPage), propertyChanged: OnSegmentIndexPropertyChanged);
+
+        private static void OnSegmentIndexPropertyChanged(BindableObject obj, object oldValue, object newValue)
+        {
+            var page = (RecommendsPage)obj;
+            page.DoLoadIllusts();
+        }
+
+        public int SegmentIndex
+        {
+            get => (int)GetValue(SegmentIndexProperty);
+            set => SetValue(SegmentIndexProperty, value);
+        }
+
+        private IllustData illustData;
 
         public RecommendsPage()
         {
+            totalBarOffset = new Thickness(0, AppShell.TotalBarOffset.Top + 40, 0, 0);
+            navigationBarOffset = new Thickness(0, AppShell.NavigationBarOffset.Top + 40, 0, 0);
+
             Resources.Add("cardView", GetCardViewTemplate());
             InitializeComponent();
         }
@@ -27,10 +47,39 @@ namespace Pixiview.Illust
             loaded = false;
         }
 
+        public override void OnOrientationChanged(Orientation orientation)
+        {
+            int columns;
+            switch (orientation)
+            {
+                case Orientation.Portrait:
+                    columns = 2;
+                    PageTopMargin = totalBarOffset;
+                    break;
+                case Orientation.PortraitUpsideDown:
+                    columns = isPhone ? 4 : 2;
+                    PageTopMargin = isPhone ? navigationBarOffset : totalBarOffset;
+                    break;
+                case Orientation.Unknown:
+                case Orientation.LandscapeLeft:
+                case Orientation.LandscapeRight:
+                default:
+                    columns = 4;
+                    PageTopMargin = navigationBarOffset;
+                    break;
+            }
+            if (Columns != columns)
+            {
+                App.DebugPrint($"ranking page, change columns to {columns}");
+                Columns = columns;
+            }
+        }
+
         protected override IEnumerable<IllustItem> DoGetIllustList(IllustData data, ICommand command)
         {
-            if (ByUser)
+            if (SegmentIndex == 1)
             {
+                // by user
                 return data.body.page.recommendUser.SelectMany(i => i.illustIds)
                     .Select(id =>
                     {
@@ -44,6 +93,7 @@ namespace Pixiview.Illust
             }
             else
             {
+                // recommends
                 return data.body.page.recommend.Select(id =>
                 {
                     var item = data.body.thumbnails.illust.FirstOrDefault(l => l.illustId == id)?.ConvertToItem();
@@ -58,7 +108,12 @@ namespace Pixiview.Illust
 
         protected override IllustData DoLoadIllustData(bool force)
         {
-            return Stores.LoadIllustData(force);
+            if (illustData != null && !force)
+            {
+                return illustData;
+            }
+            illustData = Stores.LoadIllustData(force);
+            return illustData;
         }
 
         private void Refresh_Clicked(object sender, EventArgs e)
diff --git a/Pixiview/Illust/ViewIllustPage.xaml.cs b/Pixiview/Illust/ViewIllustPage.xaml.cs
index fac6e8b..5a743c5 100644
--- a/Pixiview/Illust/ViewIllustPage.xaml.cs
+++ b/Pixiview/Illust/ViewIllustPage.xaml.cs
@@ -187,14 +187,14 @@ namespace Pixiview.Illust
                 item.OriginalUrl = p.urls.original;
             }
 
-            DoLoadImage(0);
+            DoLoadImage(0, true);
             if (items.Length > 1)
             {
                 DoLoadImage(1);
             }
         }
 
-        private void DoLoadImage(int index)
+        private void DoLoadImage(int index, bool force = false)
         {
             var items = Illusts;
             if (index < 0 || index >= items.Length)
@@ -204,10 +204,13 @@ namespace Pixiview.Illust
             }
 
             var item = items[index];
-            if (item.Loading || (index > 0 && item.Image != null))
+            if (!force)
             {
-                App.DebugPrint($"skipped, loading or already loaded, index: {index}, loading: {item.Loading}");
-                return;
+                if (item.Loading || (index > 0 && item.Image != null))
+                {
+                    App.DebugPrint($"skipped, loading or already loaded, index: {index}, loading: {item.Loading}");
+                    return;
+                }
             }
             item.Loading = true;
             var image = Stores.LoadPreviewImage(item.PreviewUrl);
diff --git a/Pixiview/UI/SegmentedControl.cs b/Pixiview/UI/SegmentedControl.cs
new file mode 100644
index 0000000..c472618
--- /dev/null
+++ b/Pixiview/UI/SegmentedControl.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using Xamarin.Forms;
+
+namespace Pixiview.UI
+{
+    public class SegmentedControl : View, IViewContainer<SegmentedControlOption>
+    {
+        public IList<SegmentedControlOption> Children { get; set; }
+
+        public SegmentedControl()
+        {
+            Children = new List<SegmentedControlOption>();
+        }
+
+        public static readonly BindableProperty TintColorProperty = BindableProperty.Create(
+            nameof(TintColor), typeof(Color), typeof(SegmentedControl));
+        public static readonly BindableProperty DisabledColorProperty = BindableProperty.Create(
+            nameof(DisabledColor), typeof(Color), typeof(SegmentedControl));
+        public static readonly BindableProperty SelectedTextColorProperty = BindableProperty.Create(
+            nameof(SelectedTextColor), typeof(Color), typeof(SegmentedControl));
+        public static readonly BindableProperty SelectedSegmentIndexProperty = BindableProperty.Create(
+            nameof(SelectedSegmentIndex), typeof(int), typeof(SegmentedControl));
+
+        public Color TintColor
+        {
+            get => (Color)GetValue(TintColorProperty);
+            set => SetValue(TintColorProperty, value);
+        }
+        public Color DisabledColor
+        {
+            get => (Color)GetValue(DisabledColorProperty);
+            set => SetValue(DisabledColorProperty, value);
+        }
+        public Color SelectedTextColor
+        {
+            get => (Color)GetValue(SelectedTextColorProperty);
+            set => SetValue(SelectedTextColorProperty, value);
+        }
+        public int SelectedSegmentIndex
+        {
+            get => (int)GetValue(SelectedSegmentIndexProperty);
+            set => SetValue(SelectedSegmentIndexProperty, value);
+        }
+
+        public SegmentedControlOption SelectedSegment => Children[SelectedSegmentIndex];
+
+        public event EventHandler<ValueChangedEventArgs> ValueChanged;
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void SendValueChanged()
+        {
+            ValueChanged?.Invoke(this, new ValueChangedEventArgs { NewValue = SelectedSegmentIndex });
+        }
+    }
+
+    public class SegmentedControlOption : View
+    {
+        public static readonly BindableProperty TextProperty = BindableProperty.Create(
+            nameof(Text), typeof(string), typeof(SegmentedControlOption));
+
+        public string Text
+        {
+            get => (string)GetValue(TextProperty);
+            set => SetValue(TextProperty, value);
+        }
+
+        public object Value { get; set; }
+    }
+
+    public class ValueChangedEventArgs : EventArgs
+    {
+        public int NewValue { get; set; }
+    }
+}