1. 程式人生 > >自定義控制元件:視差特效

自定義控制元件:視差特效

ParallaxEffects 視差特效

  • 瞭解ImageView 的scaleType 屬性
  • 掌握ListView 的overScrollBy()方法

應用場景:QQ 空間,微信朋友圈,微博,需要快速定位的列表效果圖

介面初始化

填充ListView

自定義ParallaxListView 繼承ListView

public class ParallaxListView extends ListView {
    public ParallaxListView(Context context, AttributeSet attrs, int defStyle) {
        super
(context, attrs, defStyle); } public ParallaxListView(Context context, AttributeSet attrs) { super(context, attrs); } public ParallaxListView(Context context) { super(context); } }

填充ListView 的資料

public class Cheeses {
    public static final String[] NAMES = new
String[]{"宋江", "盧俊義", "吳用", "公孫勝", "關勝", "林沖", "秦明", "呼延灼", "花榮", "柴進", "李應", "朱仝", "魯智 深", "武松", "董平", "張清", "楊志", "徐寧", "索超", "戴宗", "劉唐", "李逵", "史進", " 穆弘", "雷橫", "李俊", "阮小二", "張橫", "阮小五", " 張順", "阮小七", "楊雄", "石秀", " 解珍", " 解寶", "燕青", "朱武", "黃信", "孫立"
, "宣贊", "郝思文", "韓滔", "彭玘", "單廷珪 ", "魏定國", "蕭讓", "裴宣", "歐鵬", "鄧飛", " 燕順", "楊林", "凌振", "蔣敬", "呂方 ", "郭盛", "安道全", "皇甫端", "王英", "扈三娘", "鮑旭", "樊瑞", "孔明", "孔亮", " 項充", "李袞", "金大堅", "馬麟", "童威", "童猛", "孟康", "侯健", "陳達", "楊春", "鄭天壽 ", "陶宗旺", "宋清", "樂和", "龔旺", "丁得孫", "穆春", "曹正", "宋萬", "杜遷", "薛永 ", "施恩", "周通", "李忠", "杜興", "湯隆", "鄒淵", "鄒潤", "朱富", "朱貴", "蔡福", "蔡慶", " 李立", "李雲", "焦挺", "石勇", "孫新", "顧大嫂", "張青", "孫二孃", " 王定六", "鬱保四", " 白勝", "時遷", "段景柱"}; }

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context=".MainActivity" >
    <com.example.parallax.widget.ParallaxListView
        android:id="@+id/plv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

MainActivity 填充資料

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_main);
    plv = (ParallaxListView) findViewById(R.id.plv);
    plv.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, Cheeses.NAMES));
}

ListView 新增Header

建立header 佈局檔案

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

    <ImageView
        android:id="@+id/iv_header"
        android:layout_width="match_parent"
        android:layout_height="160dp"
        android:contentDescription="@null"
        android:scaleType="centerCrop"
        android:src="@drawable/parallax_img"/>
</RelativeLayout>

第10 行scaleType 為圖片的填充模式

圖片填充模式對比

  • matrix:圖片寬高不變,以ImageView 左上角為基準向右向下填充ImageView
  • fixXY:圖片寬高分別拉伸或壓縮,以ImageView 左上角為基準向右向下填充滿ImageView 的寬和高
  • fitStart:圖片寬高分別拉伸或壓縮,以ImageView 左上角為基準向右向下填充滿ImageView 的寬,ImageView的高不用管
  • fitCenter:圖片寬高分別拉伸或壓縮,圖片居中顯示,填充滿ImageView 的寬,ImageView 的高不用管
  • fitEnd:圖片寬高分別拉伸或壓縮,以ImageView 左下角為基準向右向上填充滿ImageView 的寬,ImageView的高不用管
  • center:圖片寬高不變,圖片居中顯示,填充ImageView
  • centerCrop:圖片寬高分別拉伸或壓縮,圖片居中顯示,直到填充滿ImageView
  • centerInside:原圖比ImageView 小,圖片居中顯示,填充ImageView,原圖比ImageView 大,圖片寬高分別拉伸或壓縮,直到填充滿ImageView 的寬或高即可

MainActivity.java 中新增頭佈局

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_main);
    plv = (ParallaxListView) findViewById(R.id.plv);
    View headerView = View.inflate(this,R.layout.layout_header, null);
    //新增頭佈局,需要在setAdapter 前新增
    plv.addHeaderView(headerView);
    plv.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,Cheeses.NAMES));
}

下拉放大

overScrollBy()方法引數解析

ParallaxListView 需要重寫overScrollBy()方法,api 要求9 以上

/**
 * 滑動到ListView 兩端才會呼叫
 */
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX,
                               int scrollY, int scrollRangeX, int scrollRangeY,
                               int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
    //deltaY 豎直方向滑動的瞬時變化量,頂部下拉為-,底部上拉為+
    //scrollY 兩端滑動超出的距離,頂部為-,底部為+
    //scrollRangeY 豎立方向滑動的範圍
    //maxOverScrollY 豎立方向最大的滑動位置
    //isTouchEvent 是否是使用者觸控拉動,true 表示使用者手指觸控拉動,false 表示慣性
    System.out.println("deltaY:" + deltaY + " scrollY:" + scrollY
            + " scrollRangeY:" + scrollRangeY + " maxOverScrollY:"
            + maxOverScrollY + " isTouchEvent:" + isTouchEvent);
    return super.overScrollBy(deltaX, deltaY, scrollX, scrollY,
            scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}

 理解deltaY 及isTouchEvent 引數的含義

動態改變頭佈局的高度

ParallaxListView 新增setParallaxImage()方法

private ImageView headerImage;
public void setParallaxImage(ImageView imageView){
    headerImage = imageView;
}

MainActivity 呼叫ParallaxListView 的setParallaxImage()方法

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_main);
    plv = (ParallaxListView) findViewById(R.id.plv);
    View headerView = View.inflate(this,R.layout.layout_header, null);
    final ImageView headerImage = (ImageView) headerView.findViewById(R.id.iv_header);
    //等view 的樹狀結構渲染完畢時,再將headerImage 設定到plv 中
    headerImage.getViewTreeObserver().addOnGlobalLayoutListener(newOnGlobalLayoutListener() {

        @Override
        public void onGlobalLayout() {
            //寬高已經測量完畢
            plv.setParallaxImage(headerImage);
            //移除監聽,避免下次渲染時還呼叫
            headerImage.getViewTreeObserver().removeGlobalOnLayoutListener(this);
        }
    });
    //新增頭佈局,需要在setAdapter 前新增
    plv.addHeaderView(headerView);
    plv.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, Cheeses.NAMES));
}

第7-18 行view 樹狀結構渲染完畢時,再將頭佈局中ImageView 設定到ParallaxListView 中,這樣在
ParallaxListView 的setParallaxImage()方法中才能獲取到ImageView 的寬高
獲取頭部ImageView 的高度

private int orignalHeight;
private int drawableHeight;

public void setParallaxImage(ImageView imageView){
    headerImage = imageView;
    //ImageView 初始高度
    orignalHeight = imageView.getHeight();
    //圖片原始高度
    drawableHeight = imageView.getDrawable().getIntrinsicHeight();
}

頂部下拉時動態設定頭部ImageView 的高度

/**
 * 滑動到ListView 兩端才會呼叫
 */
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX,
                               int scrollY, int scrollRangeX, int scrollRangeY,
                               int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
    //deltaY 豎直方向滑動的瞬時變化量,頂部下拉為-,底部上拉為+
    //scrollY 兩端滑動超出的距離,頂部為-,底部為+
    //scrollRangeY 豎立方向滑動的範圍
    //maxOverScrollY 豎立方向最大的滑動位置
    //isTouchEvent 是否是使用者觸控拉動,true 表示使用者手指觸控拉動,false 表示慣性
    System.out.println("deltaY:" + deltaY + " scrollY:" + scrollY
            + " scrollRangeY:" + scrollRangeY + " maxOverScrollY:"
            + maxOverScrollY + " isTouchEvent:" + isTouchEvent);
    //頂部下拉,使用者觸控時,將deltaY 累加給Header
    if(deltaY < 0 && isTouchEvent){
        int newHeight = headerImage.getHeight()+Math.abs(deltaY);
        //新高度小於圖片原始高度才允許累加變化量
        if(newHeight <= drawableHeight){
            //讓新的值生效
            headerImage.getLayoutParams().height = newHeight;
            headerImage.requestLayout();
        }
    }
    return super.overScrollBy(deltaX, deltaY, scrollX, scrollY,
            scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}

第16-24 行動態設定頭部ImageView 的高度

回彈動畫

ParallaxListView 重寫onTouchEvent()方法

@Override
public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
        case MotionEvent.ACTION_UP:
            //鬆手時,把currentHeight 恢復到orignalHeight
            int currentHeight = headerImage.getHeight();
            //300->160 300,299,280,250,200,...160 隨時間生成300 到160 間的值
            ValueAnimator animator = ValueAnimator.ofInt(currentHeight,orignalHeight);
            animator.setDuration(500);
            //動畫更新的監聽
            animator.addUpdateListener(new AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    //獲取隨時間變化得到的currentHeight 到orignalHeight 間的值
                    int value = (Integer) animation.getAnimatedValue();
                    //讓新的值生效
                    headerImage.getLayoutParams().height = value;
                    headerImage.requestLayout();
                }
            });
            //設定插值器實現回彈效果
            animator.setInterpolator(new OvershootInterpolator(2));
            animator.start();
            break;
        default:
            break;
    }
    return super.onTouchEvent(ev);
}

第8-23 行手指擡起時,用屬性動畫實現headerImage 恢復到初始高度

相關推薦

定義控制元件視差特效

ParallaxEffects 視差特效 瞭解ImageView 的scaleType 屬性 掌握ListView 的overScrollBy()方法 應用場景:QQ 空間,微信朋友圈,微博,需要快速定位的列表效果圖 介面初始化 填充L

定義控制元件ListView視差動畫

效果圖 思路 在下拉過程中,不斷擴大圖片的height。下拉過程中圖片的高度=原始ImageView的高度+下拉距離,當然也可以是下拉距離/2,這樣下拉2個單位,圖片的高度才增加1個單位。所以需要先要獲取頭佈局中的ImageView,獲取原高度。 當手

定義控制元件手勢縮放移動,遮罩

import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import and

Android 定義控制元件打造流佈局實現熱門搜尋標籤

具體實現 1,自定義一個類繼承GridView /** * 自定義流佈局 * @author zhouyou */ public class ZFlowLayout extends ViewGroup{ // 儲存所有子View priva

定義控制元件側拉刪除

SwipeLayout 側拉刪除 掌握ViewDragHelper 的用法 掌握平滑動畫的原理及狀態更新事件回撥 應用場景:QQ 聊天記錄,郵件管理,需要對條目進行功能擴充套件的場景,效果圖: ViewDragHelper 初始化 建立自定義

定義控制元件QQ氣泡效果粘性控制元件的實現

學習目的 瞭解幾何圖形工具的用法 掌握畫不規則圖形的方法 應用場景:未讀提醒,效果圖: 繪製一幀的效果 畫一幀粘性控制元件的步驟分析 畫一個固定圓 畫一個拖拽圓 畫中間連線部分 將中間連線部分水平放置,四個角的座標定為固定值,

Android定義控制元件動畫類---逐幀動畫AnimationDrawable

1:概述             Android動畫包括View Animation(檢視動畫)和Property Animator(屬性動畫),而View Animation包括Tween An

Android定義控制元件Android L控制元件點選水波紋的實現(原始碼 + Demo)

Demo: 一、控制元件的流程: 大致上如下,實際是有些偏差的大家可以自己畫畫 RevealLayout()--->init()--->onMeasure()--->onLayout()--->onDraw()--->dispat

Android定義控制元件動畫類----alpha、scale、translate、rotate、set的xml屬性及用法

二、下面我們逐個講講每個標籤的屬性及用法 1、scale標籤——調節尺寸 1> 自有屬性 scale標籤是縮放動畫,可以實現動態調控制元件尺寸的效果,有下面幾個屬性: android:fromXScale    起始的X方向上相對自身的縮放比例,浮點值,比如1.0代表自身無變化,

Android定義控制元件將ViewPager封裝自己的TabPager控制元件

用途 最近專案頁面中經常出現諸如下圖的控制元件,如果為每個頁面分別寫一個將會造成非常多的重複程式碼,不利於專案的閱讀和維護,也會使專案變得非常凌亂。所以,對於這種情況我們可以進行一定的抽取,傳入相關資料後自動顯示到控制元件上。

【轉】C#定義控制元件WinForm將其它應用程式窗體嵌入自己內部

PS:文末的附件已更新,這次我放到部落格園裡面了,不會彈出廣告,放心下載,O(∩_∩)O謝謝! 這是最近在做的一個專案中提到的需求,把一個現有的窗體應用程式介面嵌入到自己開發的窗體中來,看起來就像自己開發的一樣(實際上……跟自己開發的還是有一點點區別的,就是內嵌程式和宿

Android定義控制元件進度條的四種實現方式

Progress Wheel為GitHub熱門專案,作者是:Todd-Davies,專案地址: https://github.com/Todd-Davies/ProgressWheel 前三種實現方式程式碼出自: http://stormzhang.com/ope

Android定義控制元件如何使view動起來?

本文發表於CSDN《程式設計師》 摘要 Android中的很多控制元件都有滑動功能,但是很多時候原生控制元件滿足不了需求時,就需要自定義控制元件,那麼如何能讓控制元件滑動起來呢?本文主要總結幾種可以使控制元件滑動起來的方法 實現 其實能讓view

WPF 定義控制元件的坑(蠢的定義控制元件內容不顯示)

原文: WPF 自定義控制元件的坑(蠢的:自定義控制元件內容不顯示) 自定義控制元件不顯示內容 由於工作需要在寫WPF,其中想要實現一些自己的控制元件所以直接自定義了控制元件博主是繼承了ContenControl的控制元件開始寫的但是發現不管設定Content屬性為任何都是不顯示

一起Talk Android吧(第一百回Android中使用定義控制元件

各位看官們,大家好,上一回中咱們說的是Android中使用自定義佈局的例子,這一回說的例子是Android中使用自定義控制元件。閒話休提,言歸正轉。讓我們一起Talk Android吧! 看官們,我們在上一回中通過自定義佈局巧妙地實現了分隔線,不過這個分隔線中看

Android定義控制元件 --- 定義屬性 列舉值(固定屬性值)

今天寫一個自定義控制元件,為了提高使用者使用效率,需要對一個屬性的所有可能屬性值進行列舉(即,只能選擇使用給出的屬性值) 查了很多資料,自己總結一下。 如何寫自定義控制元件就不在贅述了,網上很多大神寫的都很好,此處只說明這一種情況。 attrs.xml <?xml

Android面試準備定義控制元件

Android自定義控制元件總結 Android已經為我們提供了很多控制元件,但是大多數控制元件功能都比較單一簡單,不能滿足我們的需求,我們可以通過自定義控制元件的方式來實現自己想要的功能。 Android實現自定義控制元件的方式一般有三種,第一種是繼承現有

視錯覺從一個看似簡單的定義控制元件說起

為什麼要寫今天這篇部落格那就說來話長了,那是在一個大雪紛飛的冬天……然後……。好了,不扯淡了,直接進入今天的主題吧,這篇部落格是關於iOS自定義元件的東西。一些UI效果看起來似乎是這個樣子,其實本質不是這個樣子。在做一些UI效果時我們可以利用視錯覺的一些東西,讓使用者看到的是一個東西,其實你實現的又是一個東西

WPF定義控制元件之列表滑動特效 PowerListBox

原文: WPF自定義控制元件之列表滑動特效 PowerListBox 列表控制元件是應用程式中常見的控制元件之一,對其做一些絢麗的視覺特效,可以讓軟體增色不少。 本人網上看過一個視訊,是windows phone 7系統上的一個App的列表滾動效果,效果非常炫 現在在WPF上用ListBox重現此效

VB.NET學習筆記WinForm如何正確呼叫定義控制元件

測試環境:windows 7和Microsoft Visual Studio 2015 點選下載本文資源 在《VB.NET學習筆記:WinForm自定義DataGridView分頁組合控制元件》博文中,呼叫分頁控制元件的窗體與分頁控制元件同在一個專案裡。筆者從《一種正確呼叫自定義控制元件