水平的Recyclerview带有底线指示器

时间:2018-08-24 04:05:08

标签: android android-recyclerview

我有一个水平的recycleview,可以滚动和对齐中心。然后,我要底线指示器在单击时指示所选项目。
看起来像这样:

enter image description here

我查看了this library,但它不符合我的要求。
有实现这个想法吗?
更新:我需要保持指示器始终可见,并且在移动到上方位置(如上面的礼物)时可以平滑滚动

3 个答案:

答案 0 :(得分:2)

您可以尝试以下代码:

DateTabIndicator.java

public class DateTabIndicator extends FrameLayout implements View.OnClickListener {

    private List<Integer> days = new ArrayList<>();
    private int selectedPageIndex = 0;
    private int selectedDayIndex = 0;
    private static final int[] DAY_TV_RES_ID = {R.id.day_mon, R.id.day_tue, R.id.day_wed, R.id.day_thu, R.id.day_fri, R.id.day_sat,
            R.id.day_sun};

    public DateTabIndicator(@NonNull Context context) {
        super(context);
        init();
    }

    public DateTabIndicator(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public DateTabIndicator(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private TextView monFixedIndicator;
    private TextView tueFixedIndicator;
    private TextView wedFixedIndicator;
    private TextView thuFixedIndicator;
    private TextView friFixedIndicator;
    private TextView satFixedIndicator;
    private TextView sunFixedIndicator;
    private View lineIndicator;
    private ViewPager daysPager;
    private DaysPagerAdapter daysPagerAdapter;
    private Handler mHandler = new Handler();
    private void init() {
        addView(LayoutInflater.from(getContext()).inflate(R.layout.date_tab_indicator, this, false));
        monFixedIndicator = findViewById(R.id.mon_fixed_indicator);
        tueFixedIndicator = findViewById(R.id.tue_fixed_indicator);
        wedFixedIndicator = findViewById(R.id.wed_fixed_indicator);
        thuFixedIndicator = findViewById(R.id.thu_fixed_indicator);
        friFixedIndicator = findViewById(R.id.fri_fixed_indicator);
        satFixedIndicator = findViewById(R.id.sat_fixed_indicator);
        sunFixedIndicator = findViewById(R.id.sun_fixed_indicator);
        lineIndicator = findViewById(R.id.line_indicator);
        daysPager = findViewById(R.id.days_pager);
        daysPagerAdapter = new DaysPagerAdapter();
        daysPager.setAdapter(daysPagerAdapter);
        daysPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                selectedPageIndex = position;
                mHandler.removeCallbacks(selectDayRunnable);
                mHandler.postDelayed(selectDayRunnable,500);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
        mHandler.postDelayed(selectDayRunnable,500);
    }

    class DaysPagerAdapter extends PagerAdapter {


        @Override
        public int getCount() {
            return (int) Math.ceil(days.size() / 7f);
        }


        @NonNull
        @Override
        public Object instantiateItem(@NonNull ViewGroup container, final int position) {
            final View view = LayoutInflater.from(getContext()).inflate(R.layout.days_pager_item, container, false);
            TextView dayMonTv = view.findViewById(R.id.day_mon);
            TextView dayTueTv = view.findViewById(R.id.day_tue);
            TextView dayWedTv = view.findViewById(R.id.day_wed);
            TextView dayThuTv = view.findViewById(R.id.day_thu);
            TextView dayFriTv = view.findViewById(R.id.day_fri);
            TextView daySatTv = view.findViewById(R.id.day_sat);
            TextView daySunTv = view.findViewById(R.id.day_sun);

            //Setting Day Text
            int index = position * 7;
            dayMonTv.setText(days.size() > index ? String.valueOf(days.get(index)) : "");
            dayTueTv.setText(days.size() > (++index) ? String.valueOf(days.get(index)) : "");
            dayWedTv.setText(days.size() > (++index) ? String.valueOf(days.get(index)) : "");
            dayThuTv.setText(days.size() > (++index) ? String.valueOf(days.get(index)) : "");
            dayFriTv.setText(days.size() > (++index) ? String.valueOf(days.get(index)) : "");
            daySatTv.setText(days.size() > (++index) ? String.valueOf(days.get(index)) : "");
            daySunTv.setText(days.size() > (++index) ? String.valueOf(days.get(index)) : "");

            //Setting Day VISIBILITY
            index = position * 7;
            dayMonTv.setVisibility(days.size() > index && days.get(index) != 0 ? VISIBLE : INVISIBLE);
            dayTueTv.setVisibility(days.size() > ++index && days.get(index) != 0 ? VISIBLE : INVISIBLE);
            dayWedTv.setVisibility(days.size() > ++index && days.get(index) != 0 ? VISIBLE : INVISIBLE);
            dayThuTv.setVisibility(days.size() > ++index && days.get(index) != 0 ? VISIBLE : INVISIBLE);
            dayFriTv.setVisibility(days.size() > ++index && days.get(index) != 0 ? VISIBLE : INVISIBLE);
            daySatTv.setVisibility(days.size() > ++index && days.get(index) != 0 ? VISIBLE : INVISIBLE);
            daySunTv.setVisibility(days.size() > ++index && days.get(index) != 0 ? VISIBLE : INVISIBLE);

            //Setting Selection
            dayMonTv.setSelected(false);
            dayTueTv.setSelected(false);
            dayWedTv.setSelected(false);
            dayThuTv.setSelected(false);
            dayFriTv.setSelected(false);
            daySatTv.setSelected(false);
            daySunTv.setSelected(false);

            //Setting Click Listener
            dayMonTv.setOnClickListener(DateTabIndicator.this);
            dayTueTv.setOnClickListener(DateTabIndicator.this);
            dayWedTv.setOnClickListener(DateTabIndicator.this);
            dayThuTv.setOnClickListener(DateTabIndicator.this);
            dayFriTv.setOnClickListener(DateTabIndicator.this);
            daySatTv.setOnClickListener(DateTabIndicator.this);
            daySunTv.setOnClickListener(DateTabIndicator.this);


            view.setTag(position);
            container.addView(view);
            return view;
        }

        @Override
        public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
            container.removeView((View) object);
        }

        @Override
        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {

            return view == object;
        }

    }

    public List<Integer> getDays() {
        return days;
    }

    public void setDays(List<Integer> days) {
        this.days = days;
        daysPagerAdapter.notifyDataSetChanged();
    }

    private View prevDayTv = null;

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.day_mon:
                selectDay(v, 0);
                break;
            case R.id.day_tue:
                selectDay(v, 1);
                break;
            case R.id.day_wed:
                selectDay(v, 2);
                break;
            case R.id.day_thu:
                selectDay(v, 3);
                break;
            case R.id.day_fri:
                selectDay(v, 4);
                break;
            case R.id.day_sat:
                selectDay(v, 5);
                break;
            case R.id.day_sun:
                selectDay(v, 6);
                break;
        }

    }

    /**
     * @param dayIndex 0-6
     */
    private void selectDay(View v, int dayIndex) {
        selectedDayIndex = dayIndex;
        int dayListIndex = selectedPageIndex * 7 + dayIndex;
        if (prevDayTv != null) prevDayTv.setSelected(false);
        v.setSelected(true);
        prevDayTv = v;
        int[] location = new int[2];
        v.getLocationOnScreen(location);
        int center_point = location[0]%getWidth() + v.getWidth() / 2;
        lineIndicator.animate().x(center_point - lineIndicator.getWidth() / 2);

        if (days.size() > dayListIndex && days.get(dayListIndex)!=0) {
            //listener
        } else {
            for (int i = 0; i < 7; i++) {
                dayListIndex = selectedPageIndex * 7 + i;
                if (days.get(dayListIndex)==1 || days.size()-1 == dayListIndex) {
                    setSelectedDay(i);
                    break;
                }

            }
        }

    }

    /**
     * @param dayIndex 0-6
     */
    public void setSelectedDay(int dayIndex) {
        if (dayIndex >= 0 && dayIndex < 7) {
            selectedDayIndex = dayIndex;
            View view = daysPager.findViewWithTag(selectedPageIndex);
            selectDay(view.findViewById(DAY_TV_RES_ID[dayIndex]),dayIndex);
        }

    }
    private Runnable selectDayRunnable = new Runnable() {
        @Override
        public void run() {
            setSelectedDay(selectedDayIndex);
        }
    };

}

date_tab_indicator.xml

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

    <LinearLayout
        android:id="@+id/mon_to_sun_lay"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/mon_fixed_indicator"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textSize="10sp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="M" />

        <TextView
            android:id="@+id/tue_fixed_indicator"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textSize="10sp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="T" />

        <TextView
            android:id="@+id/wed_fixed_indicator"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textSize="10sp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="W" />

        <TextView
            android:id="@+id/thu_fixed_indicator"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="10sp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="T" />

        <TextView
            android:id="@+id/fri_fixed_indicator"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textSize="10sp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="F" />

        <TextView
            android:id="@+id/sat_fixed_indicator"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textSize="10sp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="S" />

        <TextView
            android:id="@+id/sun_fixed_indicator"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textSize="10sp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="S" />
    </LinearLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/days_pager"
        android:layout_width="match_parent"
        android:layout_height="50dp" />

    <View
        android:id="@+id/line_indicator"
        android:layout_width="15dp"
        android:layout_height="3dp"
        android:padding="5dp"
        android:background="#000000"
        />

</LinearLayout>

days_pager_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="horizontal">

    <FrameLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1">

        <TextView
            android:id="@+id/day_mon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/day_circle_bg"
            android:gravity="center"
            android:layout_gravity="center"
            android:textColor="@color/day_color_selector" />
    </FrameLayout>

    <FrameLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1">

        <TextView
            android:id="@+id/day_tue"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/day_circle_bg"
            android:gravity="center"
            android:layout_gravity="center"
            android:textColor="@color/day_color_selector" />
    </FrameLayout>

    <FrameLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1">

        <TextView
            android:id="@+id/day_wed"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/day_circle_bg"
            android:gravity="center"
            android:layout_gravity="center"
            android:textColor="@color/day_color_selector" />
    </FrameLayout>

    <FrameLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1">

        <TextView
            android:id="@+id/day_thu"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/day_circle_bg"
            android:gravity="center"
            android:layout_gravity="center"
            android:textColor="@color/day_color_selector" />
    </FrameLayout>

    <FrameLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1">

        <TextView
            android:id="@+id/day_fri"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/day_circle_bg"
            android:gravity="center"
            android:layout_gravity="center"
            android:textColor="@color/day_color_selector" />
    </FrameLayout>

    <FrameLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1">

        <TextView
            android:id="@+id/day_sat"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/day_circle_bg"
            android:gravity="center"
            android:layout_gravity="center"
            android:textColor="@color/day_color_selector" />
    </FrameLayout>

    <FrameLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1">

        <TextView
            android:id="@+id/day_sun"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/day_circle_bg"
            android:gravity="center"
            android:layout_gravity="center"
            android:textColor="@color/day_color_selector" />
    </FrameLayout>

</LinearLayout>

days_color_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:color="#000000"></item>
<item android:state_selected="false" android:color="#bdbebd"></item>
</selector>

days_circle_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <size
        android:width="40dp"
        android:height="40dp" />
    <stroke android:width="1dp"
        android:color="#bdbebd"
        />

</shape>

MainActivity.java

    public class MainActivity extends AppCompatActivity {

    private DateTabIndicator dateTabIndicator;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dateTabIndicator = findViewById(R.id.date_tab_indicator);
        dateTabIndicator.setDays(Arrays.asList(new Integer[]{0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31}));

    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:android="http://schemas.android.com/apk/res/android">
<com.karacken.datetabindicator.DateTabIndicator
    android:id="@+id/date_tab_indicator"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    />
</RelativeLayout>

输出:

enter image description here

答案 1 :(得分:0)

How to build a Horizontal ListView with RecyclerView? 检查“ Suragch”的答案,以及该答案的补充内容

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
     <RelativeLayout 
      android:layout_width="wrap_content"
      android:layout_height="match_parent">
           //use your entire xml code here plus place a image view as
       <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below = "id of the date circle"
        android:background = "add a line of length according to your requirement in drawables and assign here"
        android:visibility="set to invisible"/>
      /RelativeLayout>

然后在onClick()类内部的ViewHolder方法内部,通过调用imageView.setVisibility(View.VISIBLE)和调用notifyDataSetChanged()

将ImageView的可见性设置为可见

希望这对您有帮助...

答案 2 :(得分:0)

您可以通过触发RecycleView项目选择的更改来更改指示器位置。对于所选项目的更改,可以使用变量将所选位置保留在适配器中。当用户猛扑RecycleView时,请使用根据指示器的位置计算所选位置。