箭头在哪里?

时间:2016-07-06 21:22:42

标签: android android-calendar

编辑/注意: 我真的需要回答这个问题,而且我想留下" stock"谷歌Android API。我已经为此创造了+100的赏金,但如果我在接下来的几天内使用股票API得到一个简单的解决方案,我将再增加+100,使其价值200点。

我尝试使用Android CalendarView控件。我在NestedScrollView中使用按钮和CalendarView制作了一个小应用程序。我做了按钮,它的边距非常大,所以我可以验证滚动工作。在运行Android 6.01的三星Galaxy S5上运行正常。但是在运行4.2.2的三星S Duo(这是我的预定目标)上,没有办法提前一个月(通知本月没有箭头

这是来自运行Android 6.01的Samsung S5的屏幕截图

s5 screenshot

这是三星的Duo运行4.2.2

S Duo screenshot

content_main.xml如下所示。 。 。

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <!-- This linear layout is because the scrollview can have only 1 direct child -->
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:orientation="vertical">

        <Button
            android:id="@+id/recordEnd"
            android:layout_width="200dp"
            android:layout_height="100dp"
            android:layout_marginTop="100dp"
            android:layout_marginBottom="100dp"
            android:gravity="center"
            android:text="Record End"/>

        <CalendarView
            android:id="@+id/thecalendar"
            android:layout_width="240dp"
            android:layout_height="300dp"
            android:minDate="01/01/2016"
            android:maxDate="11/30/2016"/>
    </LinearLayout>
</android.support.v4.widget.NestedScrollView>

...在Android Studio中,设计视图显示箭头。我不知道如何调试它。

2 个答案:

答案 0 :(得分:10)

快速查看CalendarView代码,看起来日历外观是从系统推断的,我无法找到改变它的方法。您可以在下方找到如何根据mode选择日历视图:

final TypedArray a = context.obtainStyledAttributes(
        attrs, R.styleable.CalendarView, defStyleAttr, defStyleRes);
final int mode = a.getInt(R.styleable.CalendarView_calendarViewMode, MODE_HOLO);
a.recycle();

switch (mode) {
    case MODE_HOLO:
        mDelegate = new CalendarViewLegacyDelegate(
                this, context, attrs, defStyleAttr, defStyleRes);
        break;
    case MODE_MATERIAL:
        mDelegate = new CalendarViewMaterialDelegate(
                this, context, attrs, defStyleAttr, defStyleRes);
        break;
    default:
        throw new IllegalArgumentException("invalid calendarViewMode attribute");
}

修改

经过一段时间花在这个问题上我有更好的解释:

  1. 预览显示带箭头的视图,因为您尚未设置正确的API版本。如果您查看下面的图像,您会发现在Lollipop之前的版本中,按钮丢失了,在它之后,一切都很好而且很好。要更改API版本,只需单击红色突出显示的按钮,然后选择所需的API级别,即可在不同平台上准确预览xml。

    KitKat version Android N version

  2. 为什么以前版本的Material Design中缺少箭头? 在这里,我无法找到谷歌某人给出的答案,但我相信这与屏幕分辨率有某种关系(在较旧的设备上,你没有足够的空间来显示{{ 1}}就像在较新的Android版本中一样,这就是他们选择CalendarView的原因,因为它只能显示几行并且仍然完全正常运行,而使用ListView显示则会裁剪一些最后一行)。

    正如我在原帖中所说,ViewPager的风格是根据Material Design(Android 5.0+)的可用性选择的。

    旧版本(在下面找到)有一个CalendarView,并且缺少下一个/上一个按钮。由于日历是使用ListView显示的,因此ListView的父视图为CalendarView,因此您无法滚动到下个月。要解决此问题,您可以找到一些解释和解决方案here

    Scroll

    Material Design版本<TextView android:id="@+android:id/month_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:paddingTop="10dip" android:paddingBottom="10dip" style="@android:style/TextAppearance.Medium" /> <!-- This is the header representing the days of the week --> <LinearLayout android:id="@+android:id/day_names" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="6dip" android:layout_marginEnd="2dip" android:layout_marginStart="2dip" android:gravity="center" > <TextView android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:visibility="gone" /> <TextView android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" /> <TextView android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" /> <TextView android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" /> <TextView android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" /> <TextView android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" /> <TextView android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" /> <TextView android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" /> </LinearLayout> <ImageView android:layout_width="match_parent" android:layout_height="1dip" android:scaleType="fitXY" android:gravity="fill_horizontal" android:src="?android:attr/dividerHorizontal" /> <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:drawSelectorOnTop="false" android:cacheColorHint="@android:color/transparent" android:fastScrollEnabled="false" android:overScrollMode="never" /> 替换为ListView,并添加prev和next按钮。

    ViewPager

    目前,由于<android.widget.DayPickerViewPager android:id="@+id/day_picker_view_pager" android:layout_width="match_parent" android:layout_height="match_parent" /> <ImageButton android:id="@+id/prev" android:layout_width="wrap_content" android:layout_height="wrap_content" android:minWidth="48dp" android:minHeight="48dp" android:src="@drawable/ic_chevron_start" android:background="?attr/selectableItemBackgroundBorderless" android:contentDescription="@string/date_picker_prev_month_button" android:visibility="invisible" /> <ImageButton android:id="@+id/next" android:layout_width="wrap_content" android:layout_height="wrap_content" android:minWidth="48dp" android:minHeight="48dp" android:src="@drawable/ic_chevron_end" android:background="?attr/selectableItemBackgroundBorderless" android:contentDescription="@string/date_picker_next_month_button" android:visibility="invisible" /> 属性已从公共API中删除,因此无法找到CalendarView样式的方法。

      

    android.R.styleable类及其字段已从公共API中删除,以更好地确保应用程序的向前兼容性。

    话虽如此,您可以保留旧版Android版本的旧样式,因为您无法对其进行更改,但请注意,stylable不应位于ListView或者尝试找到一个稳定且更符合您需求的存储库。

  3. 编辑II:

    Scroll没有被破坏,它在所有Android版本上都能很好地运行,即使它可能会让人觉得由于使用CalendarView的实现而导致其行为被破坏。现在,&#39;让我们深入研究一下这个问题,以便每个人都能理解发生了什么:

    1. 问题没有。 1:在ListView中使用ListView 一般来说,使用嵌套的元素是一种不好的做法,因为它们无法正确处理滚动操作。

    2. 问题没有。 2:使用ScrollView并不能解决问题 从Android 5.0开始,Google添加了支持库以支持嵌套滚动,但NestedScrollView除非实现ListView,否则将无法处理滚动。为此,将NestedScrollingChild类子类化并实现接口方法,并从每个方法调用NestedScrollingChildHelper中的相应方法。完成此步骤后,您可以在ListView中使用ListView,但不能使用NestedScrollView(请参阅问题编号3)

    3. 问题没有。 3:您无法从CalendarView更改列表 真正的问题是CalendarView没有任何方法可以让您使用自己编写的自定义列表更改默认列表。假设你有这样一个方法,你可以通过用自定义的方法替换默认列表来使CalendarView工作,滚动就可以完美地工作,但不幸的是你不能。

    4. 要解决问题,您有两个选择:
        - 重新设计您的视图,使CalendarView不在其名称中包含CalendarView的类中   - 使用Pravin Divraniya的答案,这将使您的日历工作完美,但请记住,嵌套的卷轴很糟糕(特别是在屏幕较小的旧Android设备上)

答案 1 :(得分:8)

Iulian Popescu的一个很好而深刻的解释,我只是想简化它。首先,我想澄清一些事情。

  1. 根据this官方Android开发人员链接,CalenderView小部件的确切外观和交互模型可能因操作系统版本和主题(例如Holo与Material)而异。
  2. 由于Iulian Popescu粘贴了来自android.widget.CalendarView类Android的代码,您可以看到CalendarViewLegacyDelegate类负责在HOLO主题和CalendarViewMaterialDelegate类的情况下呈现CalenderView负责在MATERIAL主题的情况下渲染CalenderView。我再次发布该代码仅供参考。
  3. public CalendarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
            final TypedArray a = context.obtainStyledAttributes(
                    attrs, R.styleable.CalendarView, defStyleAttr, defStyleRes);
            final int mode = a.getInt(R.styleable.CalendarView_calendarViewMode, MODE_HOLO);
            a.recycle();
            switch (mode) {
                case MODE_HOLO:
                    mDelegate = new CalendarViewLegacyDelegate(
                            this, context, attrs, defStyleAttr, defStyleRes);
                    break;
                case MODE_MATERIAL:
                    mDelegate = new CalendarViewMaterialDelegate(
                            this, context, attrs, defStyleAttr, defStyleRes);
                    break;
                default:
                    throw new IllegalArgumentException("invalid calendarViewMode attribute");
            }
        }
    
    1. CalendarViewMaterialDelegate(android.widget.CalendarViewMaterialDelegate)类中,我们可以看到DayPickerView(android.widget.DayPickerView)类用作渲染我们在Material中可以看到的日历视图的容器theme.In DayPickerView class ViewPager用于在一个页面中显示一个月。对于下一个和上一个,还有两个ImageButton。由于有两个按钮可以更改月份,因此不会产生任何问题,并且可以在MATERIAL主题中正常工作。
    2.     private final ViewPager mViewPager;
          private final ImageButton mPrevButton;
          private final ImageButton mNextButton;
      
      1. 正如我们在CalendarViewLegacyDelegate(android.widget.CalendarViewLegacyDelegate)类中看到的,ListView用于显示CalenderView中的周列表(垂直滚动)。上一页和下一页没有任何ImageButton,因为它会垂直滚动。
      2. /**
             * The adapter for the weeks list.
             */
            private WeeksAdapter mAdapter;
        
            /**
             * The weeks list.
             */
            private ListView mListView;
        

        根据此Android版开发人员网站的link,我们绝不应将ScrollViewListView一起使用,因为ListView负责自己的垂直滚动。因此,HOLO主题CalenderViewScrollView内使用时会出现意外行为。

        <强>解决方案: -

        您可以使用以下给定的自定义滚动视图类而不是NestedScrollView类。在CalenderView主题的情况下,它会使HOLO垂直滚动平滑。

        public class VerticalScrollView extends ScrollView{
        
            public VerticalScrollView(Context context) {
                super(context);
            }
        
            public VerticalScrollView(Context context, AttributeSet attrs) {
                super(context, attrs);
            }
        
            public VerticalScrollView(Context context, AttributeSet attrs, int defStyle) {
                super(context, attrs, defStyle);
            }
        
            @Override
            public boolean onInterceptTouchEvent(MotionEvent ev) {
                final int action = ev.getAction();
                switch (action)
                {
                    case MotionEvent.ACTION_DOWN:
                        super.onTouchEvent(ev);
                        break;
        
                    case MotionEvent.ACTION_MOVE:
                        return false; // redirect MotionEvents to ourself
        
                    case MotionEvent.ACTION_CANCEL:
                        super.onTouchEvent(ev);
                        break;
        
                    case MotionEvent.ACTION_UP:
                        return false;
        
                    default: 
                        break;
                }
        
                return false;
            }
        
            @Override
            public boolean onTouchEvent(MotionEvent ev) {
                super.onTouchEvent(ev);
                return true;
            }
        }
        

        我希望这会清除你的疑虑。