# MyAndroid **Repository Path**: lc951/my-android ## Basic Information - **Project Name**: MyAndroid - **Description**: 100个经典UI设计模板,干货满满。拿来即用 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 18 - **Forks**: 6 - **Created**: 2022-01-13 - **Last Updated**: 2025-03-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: Android, AndroidUI, 卡片叠层 ## README # MyAndroid #### 介绍 100个经典UI设计模板,干货满满。拿来即用 #### 软件架构 1. app模块为DEMOs集 2. 每个Activity对应这至少一个UI效果 #### 安装教程 1. git clone https://gitee.com/lc951/my-android.git #### 使用说明 1. IDE:Android studio 构建 2. 如有问题请提交wiki里 #### 7、图片装饰 文字、水印、边框 ![](./static/decorate_imageview.gif) #### 6、首页布局效果 ![](./static/index_scorll.gif) #### 5、卡片叠加效果 见效果图: ![](./static/cardoverlay_lan.gif) ![](./static/cardoverlay_por.gif) 详情看博客: [【MyAndroid】viewpage+cardView卡片叠层效果展示(2)--100个经典UI设计模板(98/100)](https://editor.csdn.net/md/?articleId=125457925) #### 1、轮播图1 ![轮播图](./static/轮播图_2022-01-13-14-06-11.gif) 参考代码示例如下: ``` ImageView iv1 = (ImageView) LayoutInflater.from(this).inflate(R.layout.banner_item,bannerViewPager,false); ImageView iv2 = (ImageView) LayoutInflater.from(this).inflate(R.layout.banner_item,bannerViewPager,false); ImageView iv3 = (ImageView) LayoutInflater.from(this).inflate(R.layout.banner_item,bannerViewPager,false); ImageView iv4 = (ImageView) LayoutInflater.from(this).inflate(R.layout.banner_item,bannerViewPager,false); ImageView iv5 = (ImageView) LayoutInflater.from(this).inflate(R.layout.banner_item,bannerViewPager,false); final ImageView iv6 = (ImageView) LayoutInflater.from(this).inflate(R.layout.banner_item,bannerViewPager,false); iv1.setImageResource(R.mipmap.ic_img01); iv2.setImageResource(R.mipmap.ic_img02); iv3.setImageResource(R.mipmap.ic_img03); iv4.setImageResource(R.mipmap.ic_img04); iv5.setImageResource(R.mipmap.ic_img05); iv6.setImageResource(R.mipmap.ic_img06); //一开始只添加5个Item final List mViews = new ArrayList<>(); mViews.add(iv1); mViews.add(iv2); mViews.add(iv3); mViews.add(iv4); mViews.add(iv5); bannerViewPager = findViewById(R.id.banner); ViewPagerAdapter mAdapter = new ViewPagerAdapter(mViews, new OnPageClickListener() { @Override public void onPageClick(View view, int position) { Log.d("cylog","position:"+position); } }); bannerViewPager.setAdapter(mAdapter); ``` ##### 轮播图2 BannerViewPagerDemo2 1. 优雅的实现手动滑到最后一页再向后滑动回到第一页 2. 自动滑动优雅平缓实现且平缓的和手动滑动切换 ###### 优雅的实现手动滑到最后一页再向后滑动回到第一页 ``` int scrollState = ViewPager.SCROLL_STATE_IDLE; private int lastValue = -1; private boolean canMove = true; ViewPager.OnPageChangeListener onPageChangeListener = new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { Log.i(TAG, "position=" + position + ",positionOffset=" + positionOffset + " ,positionOffsetPixels=" + positionOffsetPixels); if (scrollState == ViewPager.SCROLL_STATE_DRAGGING) { if (lastValue > positionOffsetPixels) { Log.d(TAG, "向右滑动"); } else if (lastValue < positionOffsetPixels) { Log.d(TAG, "向左滑动"); } else { Log.e(TAG, "暂无法判断滑动方向"); } if (0.0f == positionOffset && 0 == positionOffsetPixels) { canMove = false; } else { canMove = true; } } lastValue = positionOffsetPixels; } @Override public void onPageSelected(int i) { Log.d(TAG, "onPageSelected index=" + i); setSelectedIndicator(i); } @Override public void onPageScrollStateChanged(int i) { Log.d(TAG, "onPageScrollStateChanged i=" + i); if (ViewPager.SCROLL_STATE_DRAGGING == scrollState && i == ViewPager.SCROLL_STATE_IDLE && !canMove ) { if ( 0==viewPager.getCurrentItem() ) { Log.d(TAG, "已在第一页了" + viewPager.getCurrentItem()); }else{ Log.d(TAG, "已在最后一页了" + viewPager.getCurrentItem()); viewPager.setCurrentItem(0); } } scrollState = i; } }; ``` 滑动到第一页或者最后一页 滑动参数 position=0,positionOffset=0.0 ,positionOffsetPixels=0 position=4,positionOffset=0.0 ,positionOffsetPixels=0 一共4页 过程中判断是从ViewPager.SCROLL_STATE_DRAGGING滑动到停止滑动ViewPager.SCROLL_STATE_IDLE,在状态还保存为ViewPager.SCROLL_STATE_DRAGGING依据canMove滑动标识为停止。 接着判断当前的页数在第一还是最后一页来判断。 ###### 自动滑动优雅平缓实现且平缓的和手动滑动切换 ``` Handler handler = new Handler(); //the interval between rollings private int mAutoRollingTime = 5000; private int mReleasingTime = 0; /** * This runnable decides the viewpager should roll to next page or wait. */ private Runnable mAutoRollingTask = new Runnable() { @Override public void run() { if (isFinishing()) return; int now = (int) System.currentTimeMillis(); int timediff = mAutoRollingTime; if (mReleasingTime != 0) { timediff = now - mReleasingTime; } if (scrollState == ViewPager.SCROLL_STATE_IDLE) { //if user's finger just left the screen,we should wait for a while. if (timediff >= mAutoRollingTime * 0.8) { if (viewPager.getCurrentItem() == mViews.size() - 1) { viewPager.setCurrentItem(0, true); } else { viewPager.setCurrentItem(viewPager.getCurrentItem() + 1, true); } } } } }; @Override public void onPageScrollStateChanged(int i) { Log.d(TAG, "onPageScrollStateChanged i=" + i); if (i!=ViewPager.SCROLL_STATE_IDLE) { handler.removeCallbacks(mAutoRollingTask); }else { handler.postDelayed(mAutoRollingTask, mAutoRollingTime); } ... ``` #### 2、多功能指示器 ![](./static/指示器.png) xml: ``` ``` java ``` PageIndicatorView pageIndicatorView = findViewById(R.id.pageIndicatorView); pageIndicatorView.setViewPager(bannerViewPager.getViewPager()); pageIndicatorView.setAnimationType(AnimationType.WORM);//动画效果设置 ``` #### 3、粘性头部可点击 ![](./static/2022-03-16-19-25-0.5-3.gif) 位置StockActivity 核心代码如下 ``` ``` java StickyHeadContainer ``` 。。。 public void scrollChild(int offset) { if (mLastOffset != offset) { mOffset = offset; ViewCompat.offsetTopAndBottom(getChildAt(0), mOffset - mLastOffset); } mLastOffset = mOffset; } public int getChildHeight() { return getChildAt(0).getHeight(); } public void onDataChange(int stickyHeadPosition) { if (mDataCallback != null && mLastStickyHeadPosition != stickyHeadPosition) { mDataCallback.onDataChange(stickyHeadPosition); } if (null == mDataCallback) { Log.w(TAG, "mDataCallback is null"); } mLastStickyHeadPosition = stickyHeadPosition; } 。。。 ``` StockActivity#initView() ``` 。。。 final StickyHeadContainer container = (StickyHeadContainer) findViewById(R.id.shc); final TextView tvStockName = (TextView) container.findViewById(R.id.tv_stock_name); final CheckBox checkBox = (CheckBox) container.findViewById(R.id.checkbox); final TextView tvMore = (TextView) container.findViewById(R.id.tv_stock_more); final ImageView more = (ImageView) container.findViewById(R.id.iv_more); checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 。。。 } }); container.setDataCallback(new StickyHeadContainer.DataCallback() { @Override public void onDataChange(int pos) { mStickyPosition = pos; StockEntity.StockInfo item = mAdapter.getData().get(pos).getData(); tvStockName.setText(item.stickyHeadName); checkBox.setChecked(item.check); } }); more.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { 。。。 } }); container.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { 。。。 } }); mRecyclerView = findViewById(R.id.recycler_view); mRecyclerView.setLayoutManager(new LinearLayoutManager(StockActivity.this, LinearLayoutManager.VERTICAL, false)); StickyItemDecoration stickyItemDecoration = new StickyItemDecoration(container, RecyclerViewAdapter.TYPE_STICKY_HEAD); stickyItemDecoration.setOnStickyChangeListener(new OnStickyChangeListener() { @Override public void onScrollable(int offset) { container.scrollChild(offset); container.setVisibility(View.VISIBLE); } @Override public void onInVisible() { container.reset(); container.setVisibility(View.INVISIBLE); } }); mRecyclerView.addItemDecoration(stickyItemDecoration); mRecyclerView.addItemDecoration(new SpaceItemDecoration(mRecyclerView.getContext())); mAdapter = new StockAdapter(null); mAdapter.setItemClickListener(new OnItemClickListener() { @Override public void onItemClick(View view, StockEntity.StockInfo data, int position) { if(data.getItemType() == RecyclerViewAdapter.TYPE_DATA) { Toast.makeText(StockActivity.this, "点击了TYPE_DATA Item", Toast.LENGTH_SHORT).show(); }else if(data.getItemType() == RecyclerViewAdapter.TYPE_STICKY_HEAD){ Toast.makeText(StockActivity.this, "点击了TYPE_STICKY_HEAD Item", Toast.LENGTH_SHORT).show(); } } }); 。。。 ``` ##### (亲测)如果不设置 mDataCallback 则不显示头部悬浮吸顶 一定要进行下面的初始化设置 ``` container.setDataCallback(new StickyHeadContainer.DataCallback() { @Override public void onDataChange(int pos) { mStickyPosition = pos; StockEntity.StockInfo item = mAdapter.getData().get(pos).getData(); tvStockName.setText(item.stickyHeadName); checkBox.setChecked(item.check); } }); ``` ``` public void onDataChange(int stickyHeadPosition) { if (mDataCallback != null && mLastStickyHeadPosition != stickyHeadPosition) { mDataCallback.onDataChange(stickyHeadPosition); } if (null == mDataCallback) { Log.w(TAG, "mDataCallback is null"); } mLastStickyHeadPosition = stickyHeadPosition; } ``` #### 4、日期时间选择器 效果如下图: ![](./static/日期时间滚轮选择器.gif) ###### 库地址 [https://github.com/ycuwq/DatePicker](https://github.com/ycuwq/DatePicker) ###### 使用 使用上比较简单 ``` ``` java ``` 实现如下接口即可 YearPicker.OnYearSelectedListener ,MonthPicker.OnMonthSelectedListener , DayPicker.OnDaySelectedListener ``` #### 参与贡献 #### 特技