Android 横向扫描的动画可以通过使用 ViewPropertyAnimator 和 ObjectAnimator 来实现。

首先,在 XML 布局文件中创建一个 ImageView,并设置其宽度为 0dp,高度为 match_parent。然后,创建一个横向的渐变色 Drawable,并将其设置为 ImageView 的背景。最后,使用 ViewPropertyAnimator 来设置 ImageView 的宽度变化,实现横向扫描的动画效果。


具体实现步骤如下:

Java

1.在 XML 布局文件中添加 ImageView 和横向渐变色 Drawable:

<ImageView    
	android:id="@+id/scan_line"    
	android:layout_width="50dp"    
	android:layout_height="match_parent"    
	android:background="@drawable/scan_gradient" />

2.创建一个横向渐变色 Drawable,命名为 scan_gradient.xml:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
  <gradient
      android:startColor="#00000000"
      android:endColor="#03A9F4"
      android:type="linear"
      android:angle="0"/>
</shape>

3.使用 ViewPropertyAnimator 来设置 ImageView 的宽度变化:

// 获取 ImageView
ImageView scanLine = findViewById(R.id.scan_line);

// 获取屏幕宽度
int screenWidth = getResources().getDisplayMetrics().widthPixels;
Log.i(getClass().getSimpleName(), "onBindViewHolder: screenWidth = "+screenWidth);
// 设置 ViewPropertyAnimator
scanLine.animate()
        .translationX(screenWidth) // 横向移动到屏幕右侧
        .setDuration(3000) // 动画时长为 3 秒
        .setInterpolator(new LinearInterpolator()) // 设置动画插值器
        .withEndAction(new Runnable() {
            @Override
            public void run() {
                // 动画结束后,重新设置 ImageView 的宽度为 0
                scanLine.setTranslationX(0);
                scanLine.animate().setStartDelay(1000).start();
            }
        })
        .start();

上述代码中,使用 setDuration 方法设置动画时长为 3 秒,使用 setInterpolator 方法设置动画插值器为 LinearInterpolator,使得动画的速度保持匀速不变。使用 withEndAction 方法设置动画结束后的回调,重新设置 ImageView 的宽度为 0,并使用 setStartDelay 方法设置动画延迟 1 秒后再次启动,实现无限循环横向扫描的动画效果。

Kotlin

  • 创建 ViewPager 和 PagerAdapter
class MyPagerAdapter(
	private val items: List<String>, fm: FragmentManager) : FragmentPagerAdapter(fm) {    
	
		override fun getItem(position: Int): Fragment {        
			return MyFragment.newInstance(items[position])    
		}    
		override fun getCount(): Int {        
			return items.size    
		}
		
	}
  • 创建 Fragment 和布局文件
class MyFragment : Fragment() {

    private lateinit var textView: TextView

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_my, container, false)
        textView = view.findViewById(R.id.text_view)
        return view
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val text = arguments?.getString(ARG_TEXT) ?: ""
        textView.text = text
    }

    companion object {
        private const val ARG_TEXT = "text"
        fun newInstance(text: String): MyFragment {
            val fragment = MyFragment()
            val args = Bundle()
            args.putString(ARG_TEXT, text)
            fragment.arguments = args
            return fragment
        }
    }
}

fragment_my.xml 布局文件:

<TextView
    android:id="@+id/text_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:textSize="24sp" />
  • 设置 ViewPager 和 PageTransformer
val viewPager = findViewById<ViewPager>(R.id.view_pager)
val items = listOf("One", "Two", "Three", "Four", "Five")
val adapter = MyPagerAdapter(items, supportFragmentManager)
viewPager.adapter = adapter
viewPager.setPageTransformer(false) { page, position ->
    val absPosition = abs(position)
    if (absPosition >= 1) {
        page.alpha = 0f
    } else {
        page.alpha = 1f - absPosition
    }
}

在这个例子中,我们使用 setPageTransformer 方法设置了一个 PageTransformer 对象,该对象实现了 transformPage 方法来控制每个页面的动画效果。在这个例子中,我们实现了一个简单的淡入淡出效果,即页面从左侧进入屏幕时逐渐变得不透明,而从右侧离开屏幕时逐渐变得透明。

06-01 22:56