android对于广告栏的要求:

无限轮播
自动加手动滑动
简单的自定义指示器样式及位置
支持本地图片及网络图片
滑动流畅,无卡顿,无闪烁
广告页面不限制个数
页面点击监听事件
简单易用,高配置,无明显bug

动画效果默认的就好

实现效果图:

前期准备工作:

1.添加类库,在build.gradle中添加对Glide (图片加载框架)的引用:

compile 'com.ydevelop:bannerlayout:1.0.4'

2.AndroidManifest.xml中开网络权限,因为需要获取网络的图片

<uses-permission android:name="android.permission.INTERNET"/>

(1)在values目录下新建一个attr.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<resources><attr name="visible_tab_count" format="integer"/><declare-styleable name="BannerLayoutStyle"><attr name="selectedIndicatorColor" format="color|reference"/><attr name="unSelectedIndicatorColor" format="color|reference"/><attr name="titleBGColor" format="color|reference"/><attr name="titleColor" format="color|reference"/><attr name="indicatorShape" format="enum"><enum name="rect" value="0"/><enum name="oval" value="1"/></attr><attr name="selectedIndicatorHeight" format="dimension|reference"/><attr name="selectedIndicatorWidth" format="dimension|reference"/><attr name="unSelectedIndicatorHeight" format="dimension|reference"/><attr name="unSelectedIndicatorWidth" format="dimension|reference"/><attr name="indicatorSpace" format="dimension|reference"/><attr name="indicatorMargin" format="dimension|reference"/><attr name="autoPlayDuration" format="integer|reference"/><attr name="scrollDuration" format="integer|reference"/><attr name="isAutoPlay" format="boolean"/><attr name="defaultImage" format="integer|reference"/></declare-styleable>
</resources>

(2)自定义一个类BannerLayout,实现轮播图效果:注意类的包名,见后面

(3)新建一个xml,引用自定义的类

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" ><com.example.administrator.testb.BannerLayout
        android:id="@+id/banner2"
        android:layout_width="match_parent"
        android:layout_height="210dp"
        app:defaultImage="@mipmap/ic_launcher"
        app:scrollDuration="1000"
        app:autoPlayDuration="3000"
        app:unSelectedIndicatorHeight="10dp"
        app:unSelectedIndicatorWidth="10dp"
        app:selectedIndicatorHeight="10dp"
        app:selectedIndicatorWidth="10dp"
        app:unSelectedIndicatorColor="#99ffffff"
        app:selectedIndicatorColor="#000000"
        app:isAutoPlay="true"
        /></LinearLayout>

(4)在MainActivity中调用类的方法

 //参考网址:https://blog.csdn.net/zhaihaohao1/article/details/70746036
 BannerLayout bannerLayout2 = (BannerLayout) findViewById(R.id.banner2);List<String> urls = new ArrayList<>();urls.add("图片1地址url");urls.add("图片2地址url");
 urls.add("图片3地址url");
 urls.add("图片4地址url");
List<String> titleas = new ArrayList<>();titleas.add("标题一");titleas.add("标题二");titleas.add("标题三");titleas.add("标题四");if (bannerLayout2 != null) {bannerLayout2.setViewUrls(MainActivity.this ,urls, titleas);bannerLayout2.setOnBannerItemClickListener(new BannerLayout.OnBannerItemClickListener() {@Override
         public void onItemClick(int position) {Toast.makeText(MainActivity.this, "position:" + position, Toast.LENGTH_SHORT).show();}});}

(5)总结

这个例子很好的实现了我们需要的效果,大家在使用的过程中切记自定义的类需要引用对应的包名,修改小圆点位置是在BannerLayout文件里面,有对应的属性,可以设置居中或者居右,每一个图片都有相对应的点击事件,非常符合我们的需求,MainActivity调用的方法可以点击进去看看,还有一个方法可以显示本地的图片。

(6)自定义的类BannerLayout:

public class BannerLayout extends RelativeLayout {private ViewPager mViewPager; // 轮播容器

    // 指示器(圆点)容器
    private LinearLayout indicatorContainer;private Drawable unSelectedDrawable;private Drawable selectedDrawable;private int WHAT_AUTO_PLAY = 1000;private boolean isAutoPlay = true; // 自动轮播

    private int itemCount;private int selectedIndicatorColor = 0xffff0000;private int unSelectedIndicatorColor = 0x88888888;private int titleBGColor = 0X33000000;private int titleColor = 0Xffffffff;private Shape indicatorShape = Shape.oval;private int selectedIndicatorHeight = 20;private int selectedIndecatorWidth = 20;private int unSelectedIndicatorHeight = 20;private int unSelectedIndecatorWidth = 20;private int autoPlayDuration = 4000;private int scrollDuration = 900;//  指示器中点和点之间的距离
    private int indicatorSpace = 15;//  指示器整体的设置
    private int indicatorMargin = 20;private static final int titlePadding = 20;private int defaultImage;private enum Shape {// 矩形 或 圆形的指示器
        rect, oval
    }private OnBannerItemClickListener mOnBannerItemClickListener;private Handler mHandler = new Handler(new Handler.Callback() {@Override
        public boolean handleMessage(Message msg) {if (msg.what == WHAT_AUTO_PLAY) {if (mViewPager != null) {mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1, true);mHandler.sendEmptyMessageDelayed(WHAT_AUTO_PLAY, autoPlayDuration);}}return false;}});public BannerLayout(Context context) {super(context);init(null, 0);}public BannerLayout(Context context, AttributeSet attrs) {super(context, attrs);init(attrs, 0);}public BannerLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(attrs, defStyleAttr);}private void init(AttributeSet attrs, int defStyleAttr) {TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.BannerLayoutStyle, defStyleAttr, 0);selectedIndicatorColor = array.getColor(R.styleable.BannerLayoutStyle_selectedIndicatorColor, selectedIndicatorColor);unSelectedIndicatorColor = array.getColor(R.styleable.BannerLayoutStyle_unSelectedIndicatorColor, unSelectedIndicatorColor);titleBGColor = array.getColor(R.styleable.BannerLayoutStyle_titleBGColor, titleBGColor);titleColor = array.getColor(R.styleable.BannerLayoutStyle_titleColor, titleColor);int shape = array.getInt(R.styleable.BannerLayoutStyle_indicatorShape, Shape.oval.ordinal());for (Shape shape1 : Shape.values()) {if (shape1.ordinal() == shape) {indicatorShape = shape1;break;}}selectedIndecatorWidth = (int) array.getDimension(R.styleable.BannerLayoutStyle_selectedIndicatorWidth, selectedIndecatorWidth);selectedIndicatorHeight = (int) array.getDimension(R.styleable.BannerLayoutStyle_selectedIndicatorHeight, selectedIndicatorHeight);unSelectedIndecatorWidth = (int) array.getDimension(R.styleable.BannerLayoutStyle_unSelectedIndicatorWidth, unSelectedIndecatorWidth);unSelectedIndicatorHeight = (int) array.getDimension(R.styleable.BannerLayoutStyle_unSelectedIndicatorHeight, unSelectedIndicatorHeight);indicatorSpace = (int) array.getDimension(R.styleable.BannerLayoutStyle_indicatorSpace, indicatorSpace);indicatorMargin = (int) array.getDimension(R.styleable.BannerLayoutStyle_indicatorMargin, indicatorMargin);autoPlayDuration = array.getInt(R.styleable.BannerLayoutStyle_autoPlayDuration, autoPlayDuration);scrollDuration = array.getInt(R.styleable.BannerLayoutStyle_scrollDuration, scrollDuration);isAutoPlay = array.getBoolean(R.styleable.BannerLayoutStyle_isAutoPlay, isAutoPlay);defaultImage = array.getResourceId(R.styleable.BannerLayoutStyle_defaultImage, defaultImage);array.recycle();LayerDrawable unSelectedLayerDrawable;LayerDrawable selectedLayerDrawable;GradientDrawable unSelectedGradientDrawable = new GradientDrawable();GradientDrawable selectedGradientDtawbale = new GradientDrawable();switch (indicatorShape) {case rect:unSelectedGradientDrawable.setShape(GradientDrawable.RECTANGLE);selectedGradientDtawbale.setShape(GradientDrawable.RECTANGLE);break;case oval:unSelectedGradientDrawable.setShape(GradientDrawable.OVAL);selectedGradientDtawbale.setShape(GradientDrawable.OVAL);break;}unSelectedGradientDrawable.setColor(unSelectedIndicatorColor);unSelectedGradientDrawable.setSize(unSelectedIndecatorWidth, unSelectedIndicatorHeight);unSelectedLayerDrawable = new LayerDrawable(new Drawable[]{unSelectedGradientDrawable});unSelectedDrawable = unSelectedLayerDrawable;selectedGradientDtawbale.setColor(selectedIndicatorColor);selectedGradientDtawbale.setSize(selectedIndecatorWidth, selectedIndicatorHeight);selectedLayerDrawable = new LayerDrawable(new Drawable[]{selectedGradientDtawbale});selectedDrawable = selectedLayerDrawable;}/**
     * 添加本地图片
     *
     * @param viewRes 图片id集合
     * @param titles  标题集合,可空
     */
    public void setViewRes(List<Integer> viewRes, List<String> titles) {List<View> views = new ArrayList<>();itemCount = viewRes.size();if (titles != null && titles.size() != viewRes.size()) {throw new IllegalStateException("views.size() != titles.size()");}// 把数量拼凑到三个以上
        if (itemCount < 1) {throw new IllegalStateException("item count not equal zero");} else if (itemCount < 2) {views.add(getFrameLayoutView(viewRes.get(0), titles != null ? titles.get(0) : null, 0));views.add(getFrameLayoutView(viewRes.get(0), titles != null ? titles.get(0) : null, 0));views.add(getFrameLayoutView(viewRes.get(0), titles != null ? titles.get(0) : null, 0));} else if (itemCount < 3) {views.add(getFrameLayoutView(viewRes.get(0), titles != null ? titles.get(0) : null, 0));views.add(getFrameLayoutView(viewRes.get(1), titles != null ? titles.get(1) : null, 1));views.add(getFrameLayoutView(viewRes.get(0), titles != null ? titles.get(0) : null, 0));views.add(getFrameLayoutView(viewRes.get(1), titles != null ? titles.get(1) : null, 1));} else {for (int i = 0; i < viewRes.size(); i++) {views.add(getFrameLayoutView(viewRes.get(i), titles != null ? titles.get(i) : null, i));}}setViews(views);}//添加网络图片路径
    public void setViewUrls(Context context,List<String> urls, List<String> titles) {List<View> views = new ArrayList<>();itemCount = urls.size();Log.e("TAG",titles.size()+"---90---"+urls.size());if (titles != null && titles.size() != itemCount) {throw new IllegalStateException("views.size() != titles.size()");}//主要是解决当item为小于3个的时候滑动有问题,这里将其拼凑成3个以上
        if (itemCount < 1) {//当item个数0
            throw new IllegalStateException("item count not equal zero");} else if (itemCount < 2) { //当item个数为1
            views.add(getFrameLayoutView(context,urls.get(0), titles != null ? titles.get(0) : null, 0));views.add(getFrameLayoutView(context,urls.get(0), titles != null ? titles.get(0) : null, 0));views.add(getFrameLayoutView(context,urls.get(0), titles != null ? titles.get(0) : null, 0));} else if (itemCount < 3) {//当item个数为2
            views.add(getFrameLayoutView(context,urls.get(0), titles != null ? titles.get(0) : null, 0));views.add(getFrameLayoutView(context,urls.get(1), titles != null ? titles.get(1) : null, 1));views.add(getFrameLayoutView(context,urls.get(0), titles != null ? titles.get(0) : null, 0));views.add(getFrameLayoutView(context,urls.get(1), titles != null ? titles.get(1) : null, 1));} else {for (int i = 0; i < urls.size(); i++) {views.add(getFrameLayoutView(context,urls.get(i), titles != null ? titles.get(i) : null, i));}}setViews(views);}private void setViews(final List<View> views) {mViewPager = new ViewPager(getContext());addView(mViewPager);setSliderTransformDuration(scrollDuration);//初始化indicatorContainer
        indicatorContainer = new LinearLayout(getContext());indicatorContainer.setGravity(Gravity.CENTER_VERTICAL);LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);// 设置 指示点的位置  ALIGN_PARENT_RIGHT表示居右 CENTER_HORIZONTAL表示居中
        params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);//设置margin
        params.setMargins(indicatorMargin, indicatorMargin, indicatorMargin, indicatorMargin);//添加指示器容器布局到SliderLayout
        addView(indicatorContainer, params);//初始化指示器,并添加到指示器容器布局
        for (int i = 0; i < itemCount; i++) {ImageView indicator = new ImageView(getContext());indicator.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));indicator.setPadding(indicatorSpace, indicatorSpace, indicatorSpace, indicatorSpace);indicator.setImageDrawable(unSelectedDrawable);indicatorContainer.addView(indicator);}LoopPagerAdapter pagerAdapter = new LoopPagerAdapter(views);mViewPager.setAdapter(pagerAdapter);//设置当前item到Integer.MAX_VALUE中间的一个值,看起来像无论是往前滑还是往后滑都是ok的
        //如果不设置,用户往左边滑动的时候已经划不动了
        int targetItemPosition = Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 % itemCount;mViewPager.setCurrentItem(targetItemPosition);switchIndicator(targetItemPosition % itemCount);mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {@Override
            public void onPageSelected(int position) {switchIndicator(position % itemCount);}});startAutoPlay();}/**
     * 开始自动轮播
     */
    public void startAutoPlay() {stopAutoPlay(); // 避免重复消息
        if (isAutoPlay) {mHandler.sendEmptyMessageDelayed(WHAT_AUTO_PLAY, autoPlayDuration);}}@Override
    protected void onWindowVisibilityChanged(int visibility) {super.onWindowVisibilityChanged(visibility);if (visibility == VISIBLE) {startAutoPlay();} else {stopAutoPlay();}}/**
     * 停止自动轮播
     */
    public void stopAutoPlay() {if (isAutoPlay) {mHandler.removeMessages(WHAT_AUTO_PLAY);}}private void setSliderTransformDuration(int scrollDuration) {try {Field mScroller = ViewPager.class.getDeclaredField("mScroller");mScroller.setAccessible(true);FixedSpeedScroller fixedSpeedScroller = new FixedSpeedScroller(mViewPager.getContext(), null, scrollDuration);mScroller.set(mViewPager, fixedSpeedScroller);} catch (Exception e) {e.printStackTrace();}}@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:stopAutoPlay();break;case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP:startAutoPlay();break;}return super.dispatchTouchEvent(ev);}/**
     * 切换指示器状态
     *
     * @param currentPosition 当前位置
     */
    private void switchIndicator(int currentPosition) {for (int i = 0; i < indicatorContainer.getChildCount(); i++) {((ImageView) indicatorContainer.getChildAt(i)).setImageDrawable(i == currentPosition ? selectedDrawable : unSelectedDrawable);}}public void setOnBannerItemClickListener(OnBannerItemClickListener onBannerItemClickListener) {this.mOnBannerItemClickListener = onBannerItemClickListener;}@NonNull
    private FrameLayout getFrameLayoutView(Context context, String url, String title, final int position) {FrameLayout frameLayout = new FrameLayout(getContext());FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);layoutParams.gravity = Gravity.CENTER;ImageView imageView = new ImageView(getContext());frameLayout.addView(imageView);frameLayout.setOnClickListener(new OnClickListener() {@Override
            public void onClick(View v) {if (mOnBannerItemClickListener != null) {mOnBannerItemClickListener.onItemClick(position);}}});imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);if (defaultImage != 0){Glide.with(getContext()).load(url).placeholder(defaultImage).centerCrop().into(imageView);}else {Glide.with(getContext()).load(url).centerCrop().into(imageView);}if (!TextUtils.isEmpty(title)) {TextView textView = new TextView(getContext());textView.setText(title);textView.setTextColor(titleColor);textView.setPadding(titlePadding, titlePadding, titlePadding, titlePadding);textView.setBackgroundColor(titleBGColor);textView.getPaint().setFakeBoldText(true);layoutParams.gravity = Gravity.BOTTOM;frameLayout.addView(textView, layoutParams);}return frameLayout;}@NonNull
    private FrameLayout getFrameLayoutView(Integer res, String title, final int position) {FrameLayout frameLayout = new FrameLayout(getContext());FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);layoutParams.gravity = Gravity.CENTER;ImageView imageView = new ImageView(getContext());frameLayout.addView(imageView);frameLayout.setOnClickListener(new OnClickListener() {@Override
            public void onClick(View v) {if (mOnBannerItemClickListener != null) {mOnBannerItemClickListener.onItemClick(position);}}});imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);Glide.with(getContext()).load(res).centerCrop().into(imageView);if (!TextUtils.isEmpty(title)) {TextView textView = new TextView(getContext());textView.setText(title);textView.setTextColor(titleColor);textView.setPadding(titlePadding, titlePadding, titlePadding, titlePadding);textView.setBackgroundColor(titleBGColor);textView.getPaint().setFakeBoldText(true);layoutParams.gravity = Gravity.BOTTOM;frameLayout.addView(textView, layoutParams);}return frameLayout;}public interface OnBannerItemClickListener {void onItemClick(int position);}public class LoopPagerAdapter extends PagerAdapter {private List<View> views;public LoopPagerAdapter(List<View> views) {this.views = views;}@Override
        public int getCount() {//Integer.MAX_VALUE = 2147483647
            return Integer.MAX_VALUE;}@Override
        public boolean isViewFromObject(View view, Object object) {return view == object;}@Override
        public Object instantiateItem(ViewGroup container, int position) {if (views.size() > 0) {//position % view.size()是指虚拟的position会在[0,view.size())之间循环
                View view = views.get(position % views.size());if (container.equals(view.getParent())) {container.removeView(view);}container.addView(view);return view;}return null;}@Override
        public void destroyItem(ViewGroup container, int position, Object object) {}}public class FixedSpeedScroller extends Scroller {private int mDuration = 1000;public FixedSpeedScroller(Context context) {super(context);}public FixedSpeedScroller(Context context, Interpolator interpolator) {super(context, (android.view.animation.Interpolator) interpolator);}public FixedSpeedScroller(Context context, Interpolator interpolator, int duration) {this(context, interpolator);mDuration = duration;}@Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {// Ignore received duration, use fixed one instead
            super.startScroll(startX, startY, dx, dy, mDuration);}@Override
        public void startScroll(int startX, int startY, int dx, int dy) {// Ignore received duration, use fixed one instead
            super.startScroll(startX, startY, dx, dy, mDuration);}}}

实现android广告栏效果相关推荐

  1. android 广告栏效果,叫教你打造一个滑动悬浮置顶的视觉效果,给你的广告栏增加一些特色...

    一个滑动悬浮置顶的View,通过自定义ScrollView来实现一个精美的固定悬浮效果 效果图: 这个特效其实没有那么复杂! 思路: 自定义ListView对头布局进行处理 自定义 RecycleVi ...

  2. android+广告栏效果,Android自定义控件之广告条滚动效果

    在一些电子商务网站上经常能够看到一些滚动的广告条,许多软件在首次使用时也有类似的广告条,如图: 其实在github上有实现这种效果的控件,不过这东西做起来也是很简单,我们今天就来看看该怎么做. 先来看 ...

  3. android 广告栏效果,实现android广告栏效果

    public classBannerLayout extendsRelativeLayout { privateViewPager mViewPager; // 轮播容器// 指示器(圆点)容器pri ...

  4. Android一步一步实现一款实用的Android广告栏

    源码:BannerLayoutDemo 有图有真相: bannerLayoutDemo 开源界有一句很有名的话叫"不要重复发明轮子",当然,我今天的观点不是要反驳这句话,轮子理论给 ...

  5. Android 抽屉效果Demo

    2019独角兽企业重金招聘Python工程师标准>>> Android 抽屉效果Demo. 转载:http://www.adobex.com/android/source/detai ...

  6. android中倒计时动画,简单实现Android倒计时效果

    本文实例为大家分享了Android倒计时效果的具体代码,供大家参考,具体内容如下 需求: a.在后台添加时,如果是今日直播,则需要添加开始时间(精确到秒): b.离开始时间超过1天,显示为:" ...

  7. 使用CollectionView简单实现轮播广告栏效果

    使用CollectionView简单实现轮播广告栏效果 当自己在做项目时感觉老是得重复写一些广告栏,嫌麻烦,所以自己简单封装了一个广告栏,不足之处希望大家指出,下面简单写下部分代码供大家参考: - V ...

  8. 程序员表白神器。安卓程序员表白软件。程序员追女友利器=android+雪花效果+彩色气泡+心形花园+心形玫瑰花+相爱天数计时器

    程序员表白神器.安卓程序员表白软件.程序员追女友利器=android+雪花效果+彩色气泡+心形花园+心形玫瑰花 +相爱天数计时器. APK下载(把这个给女朋友,她一定会高兴的):http://down ...

  9. android 圆角效果

    android 圆角效果 最近做一个效果,要一个上边两个角为圆角,下面两个角为直角的四边形白色背景: 如下图: 这里用到了shape属性中的corners 属性, api原文中是这样: <cor ...

最新文章

  1. 在mac上安装 docker
  2. c语言读h5文件,我利用C语言实现SHA-256算法,需要从一个txt文件中读出数据并把...
  3. Android studio2.3.3升级3.1.2坑
  4. linux视频教程之vsftp_B
  5. 从源码角度分析下 micrometer 自定义 metrics endpoint 和 springboot actuator
  6. 玩转HTML5应用实战:灵活拖拉文件
  7. 5-13自定义sink到MySQL.
  8. matlab晶闸管没有触发就导通,单相全控桥式晶闸管整流电路(纯电阻负载)
  9. Mac OSX上卸载Anaconda
  10. 如何用计算机进行机械制图,机械制图与机械CAD的有机结合的探究
  11. 香格里拉是如何策划成功的?
  12. laravel框架的whereIn条件或者where条件里面的in条件怎么写
  13. Android 扫码登录
  14. 下肢静脉曲张的病因具体有哪些?
  15. 谷歌地图JavaScript API第3版 地理编码服务
  16. 浏览器Goole Chrome调试工具
  17. 中国式父母计算机科学家攻略,中国式家长攻略大全:全结局解锁技巧汇总[多图]...
  18. 计算机基础之流水线(七)
  19. 原神私服搭建二: 搭建服务端
  20. JAVA毕设项目社区生鲜电商平台(java+VUE+Mybatis+Maven+Mysql)

热门文章

  1. 微信小程序中的空格怎么打
  2. KT148A语音芯片SOP外挂功放芯片8002D的说明_V1
  3. 景点接口 查询携程旅游门票景点详情
  4. k8s(kubernetes)部署nacos(3各节点....N各节点均可以)集群
  5. mysql面试题总结
  6. 哪些数码好物值得在开学季入手,推荐几款数码好物
  7. 安卓设备脱离pc自动化测试,Termux模拟器下python+uiautomator2的环境设置。本人亲测,踩坑总结。
  8. 3D Touch大法
  9. plsql不读操作系统环境变量_64位Oracle客户端上PLSQL无法识别ORACLE_HOME解决方案
  10. 体验论文新神器!AMiner人工智能工具,自动溯源论文来龙去脉