1. 程式人生 > 程式設計 >Android仿直播類app贈送禮物功能

Android仿直播類app贈送禮物功能

直播介面

實現的是播放本地的視訊檔案:

/**
 * 直播介面,用於對接直播功能
 */
public class LiveFrag extends Fragment {

 private ImageView img_thumb;
 private VideoView video_view;

 @Nullable
 @Override
 public View onCreateView(@NonNull LayoutInflater inflater,@Nullable ViewGroup container,@Nullable Bundle savedInstanceState) {
 View view = inflater.inflate(R.layout.frag_live,null);
 img_thumb = view.findViewById(R.id.img_thumb);
 img_thumb.setVisibility(View.GONE);
 video_view = view.findViewById(R.id.video_view);
 video_view.setVisibility(View.VISIBLE);
 video_view.setVideoURI(Uri.parse("android.resource://" + getActivity().getPackageName() + "/" + R.raw.video_1));
 video_view.start();
 video_view.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
 @Override
 public void onCompletion(MediaPlayer mp) {
 video_view.setVideoURI(Uri.parse("android.resource://" + getActivity().getPackageName() + "/" + R.raw.video_1));
 //或 //mVideoView.setVideoPath(Uri.parse(_filePath));
 video_view.start();
 }
 });
 return view;
 }
}

佈局檔案 frag_live.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:orientation="vertical">
 <VideoView
 android:id="@+id/video_view"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:clickable="false"
 android:focusable="false"
 android:visibility="gone" />
 <ImageView
 android:id="@+id/img_thumb"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:clickable="false"
 android:focusable="false"
 android:scaleType="centerCrop"
 android:src="@mipmap/img_video_1"
 android:visibility="visible" />
</LinearLayout>

滑動隱藏效果

需要實現的效果如下:

Android仿直播類app贈送禮物功能

自定義DialogFragment,使用ViewPager,第一個為空的Fragment,第二個為我們需要的Fragment,左右滑動來切換顯示和隱藏效果。

觀眾功能互動頁面 InteractiveFrag 如下:

/**
 * 觀眾功能互動頁面,滑動隱藏效果
 */
public class InteractiveFrag extends DialogFragment {

 public View view;
 public Context myContext;
 private ViewPager vp_interactive;
 private LayerFrag layerFrag;

 @Override
 public View onCreateView(LayoutInflater inflater,@Nullable Bundle savedInstanceState) {
 view = inflater.inflate(R.layout.frag_interactive,null);
 // 初始化
 initView();
 initData();
 return view;
 }

 /**
 * 初始化View
 */
 public void initView() {
 vp_interactive = view.findViewById(R.id.vp_interactive);
 }

 /**
 * 初始化資料
 */
 public void initData() {
 // EmptyFrag:什麼都沒有
 // LayerFrag:互動介面
 // 這樣就達到了滑動隱藏互動的需求
 vp_interactive.setAdapter(new FragmentPagerAdapter(getChildFragmentManager()) {
 @Override
 public int getCount() {
 return 2;
 }

 @Override
 public Fragment getItem(int position) {
 if (position == 0) {
 return new EmptyFrag(); // 返回空介面的fragment
 } else if (position == 1) {
 return layerFrag = new LayerFrag(); // 返回互動介面的frag
 } else { // 設定預設

 return new EmptyFrag();
 }
 }
 });
 // 設定預設顯示互動介面
 vp_interactive.setCurrentItem(1);

 // 同時將介面改為resize已達到軟鍵盤彈出時Fragment不會跟隨移動
 getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
 }

 @Override
 public Dialog onCreateDialog(Bundle savedInstanceState) {

 // 設定DialogFragment的樣式,這裡的程式碼最好還是用我的,大家不要改動
 Dialog dialog = new Dialog(getActivity(),R.style.MainDialog) {

 @Override
 public void onBackPressed() {
 super.onBackPressed();
 getActivity().finish();
 }
 };
 return dialog;
 }
}

frag_interactive.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:orientation="vertical" >

 <androidx.viewpager.widget.ViewPager
 android:id="@+id/vp_interactive"
 android:layout_width="match_parent"
 android:layout_height="match_parent" />
</LinearLayout>

使用者互動頁 LayerFrag:

public class LayerFrag extends Fragment {
 @Nullable
 @Override
 public View onCreateView(@NonNull LayoutInflater inflater,@Nullable Bundle savedInstanceState) {
 return inflater.inflate(R.layout.frag_layer,null);
 }
}

frag_layer:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical">
 <LinearLayout
 android:id="@+id/ll_anchor"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:gravity="center_vertical"
 android:orientation="horizontal"
 android:paddingLeft="10dp"
 android:paddingTop="10dp">
 <RelativeLayout
 android:layout_width="wrap_content"
 android:layout_height="wrap_content">
 <LinearLayout
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_centerVertical="true"
 android:background="@drawable/bg_radius_top_black"
 android:gravity="center_vertical"
 android:orientation="vertical"
 android:paddingLeft="55dp"
 android:paddingTop="2dp"
 android:paddingRight="10dp"
 android:paddingBottom="2dp">
 <TextView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="十三妹哦"
 android:textColor="@android:color/white"
 android:textSize="12sp" />
 <LinearLayout
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:gravity="center_vertical"
 android:orientation="horizontal">
 <ImageView
 android:layout_width="35dp"
 android:layout_height="20dp"
 android:src="@drawable/hani_icon_tag_exp" />
 <TextView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginLeft="5dp"
 android:text="17萬"
 android:textColor="@android:color/white"
 android:textSize="10sp" />
 </LinearLayout>
 </LinearLayout>
 <com.hongx.zhibo.utils.CircleImageView
 android:id="@+id/lv_anchorIcon"
 android:layout_width="50dp"
 android:layout_height="50dp"
 android:src="@drawable/zf"
 app:border_color="@color/colorWhite"
 app:border_width="1dp" />
 </RelativeLayout>
 <com.hongx.zhibo.utils.HorizontalListView
 android:id="@+id/hlv_audience"
 android:layout_width="match_parent"
 android:layout_height="45dp"
 android:layout_marginLeft="10dp" />
 </LinearLayout>
 <RelativeLayout
 android:id="@+id/rl_num"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_below="@+id/ll_anchor"
 android:layout_marginTop="5dp"
 android:paddingLeft="10dp"
 android:paddingRight="10dp">
 <LinearLayout
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:background="@drawable/bg_radius_bottom_pink"
 android:gravity="center_vertical"
 android:paddingLeft="10dp"
 android:paddingTop="2dp"
 android:paddingRight="10dp"
 android:paddingBottom="2dp">
 <ImageView
 android:layout_width="20dp"
 android:layout_height="10dp"
 android:src="@drawable/molive_icon_charm_lv_20" />
 <TextView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginLeft="5dp"
 android:text="小時榜單第5名"
 android:textColor="#fff"
 android:textSize="10sp" />
 </LinearLayout>
 <TextView
 android:id="@+id/tv_momocode"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignParentRight="true"
 android:layout_centerVertical="true"
 android:background="@drawable/bg_radius_top_black"
 android:paddingLeft="10dp"
 android:paddingTop="2dp"
 android:paddingRight="10dp"
 android:paddingBottom="2dp"
 android:text="MoMo: 12345678"
 android:textColor="@android:color/white"
 android:textSize="10sp" />
 </RelativeLayout>
 <LinearLayout
 android:id="@+id/ll_gift_group"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_above="@+id/lv_message"
 android:layout_marginTop="10dp"
 android:layout_marginBottom="10dp"
 android:animateLayoutChanges="true"
 android:gravity="top"
 android:orientation="vertical" />
 <ListView
 android:id="@+id/lv_message"
 android:layout_width="230dp"
 android:layout_height="150dp"
 android:layout_above="@+id/fl_bottom"
 android:layout_marginLeft="10dp"
 android:cacheColorHint="#00000000"
 android:divider="@null"
 android:dividerHeight="5dp"
 android:listSelector="#00000000"
 android:scrollbarStyle="outsideOverlay"
 android:scrollbars="none"
 android:transcriptMode="normal" />
 <FrameLayout
 android:id="@+id/fl_bottom"
 android:layout_width="match_parent"
 android:layout_height="70dp"
 android:layout_alignParentStart="true"
 android:layout_alignParentBottom="true">
 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@android:color/transparent"
 android:gravity="center_vertical"
 android:orientation="horizontal"
 android:paddingLeft="10dp"
 android:paddingRight="10dp">
 <Button
 android:id="@+id/tv_chat"
 android:layout_width="40dp"
 android:layout_height="70dp"
 android:gravity="center"
 android:text="聊天"
 android:textColor="#333"
 android:textSize="10sp" />
 <View
 android:layout_width="0dp"
 android:layout_height="1dp"
 android:layout_weight="1" />
 <Button
 android:id="@+id/btn_gift01"
 android:layout_width="40dp"
 android:layout_height="70dp"
 android:layout_marginRight="5dp"
 android:gravity="center"
 android:text="送香皂"
 android:textColor="#333"
 android:textSize="12sp" />
 <Button
 android:id="@+id/btn_gift02"
 android:layout_width="40dp"
 android:layout_height="70dp"
 android:layout_marginRight="5dp"
 android:gravity="center"
 android:text="送玫瑰"
 android:textColor="#333"
 android:textSize="12sp" />
 <Button
 android:id="@+id/btn_gift03"
 android:layout_width="40dp"
 android:layout_height="70dp"
 android:layout_marginRight="5dp"
 android:gravity="center"
 android:text="送愛心"
 android:textColor="#333"
 android:textSize="12sp" />
 <Button
 android:id="@+id/btn_gift04"
 android:layout_width="40dp"
 android:layout_height="70dp"
 android:layout_marginRight="5dp"
 android:gravity="center"
 android:text="送蛋糕"
 android:textColor="#333"
 android:textSize="12sp" />
 </LinearLayout>
 <LinearLayout
 android:id="@+id/ll_inputparent"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:layout_marginTop="5dp"
 android:background="@android:color/white"
 android:paddingLeft="10dp"
 android:paddingRight="10dp"
 android:visibility="gone">
 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:gravity="center_vertical"
 android:orientation="horizontal">
 <EditText
 android:id="@+id/et_chat"
 android:layout_width="0dp"
 android:layout_height="wrap_content"
 android:layout_weight="1"
 android:background="@android:color/white"
 android:hint="在此輸入你要說的話!"
 android:maxLength="30"
 android:paddingTop="10dp"
 android:paddingBottom="10dp"
 android:textColor="#888889"
 android:textColorHint="#c8c8c8"
 android:textSize="12sp" />
 <TextView
 android:id="@+id/tv_send"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginLeft="10dp"
 android:background="@android:color/holo_blue_bright"
 android:paddingLeft="10dp"
 android:paddingTop="5dp"
 android:paddingRight="10dp"
 android:paddingBottom="5dp"
 android:text="傳送"
 android:textColor="@android:color/white"
 android:textSize="12sp" />
 </LinearLayout>
 </LinearLayout>
 </FrameLayout>
</RelativeLayout>

EmptyFrag:

/**
 * 空的fragment
 */
public class EmptyFrag extends Fragment {
 @Nullable
 @Override
 public View onCreateView(@NonNull LayoutInflater inflater,@Nullable Bundle savedInstanceState) {
 return inflater.inflate(R.layout.frag_empty,null);
 }
}

frag_empty.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:background="@android:color/transparent"
 android:orientation="vertical">
</LinearLayout>

在MainActivity中使用FrameLayout佈局,將觀眾功能互動頁面 InteractiveFrag 覆蓋在 直播頁面LiveFrag上面。

MainActivity:

public class MainActivity extends AppCompatActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 // 載入直播fragment
 LiveFrag liveFrag = new LiveFrag();
 getSupportFragmentManager().beginTransaction().add(R.id.fl_root,liveFrag).commit();
 // 載入
 new InteractiveFrag().show(getSupportFragmentManager(),"InteractiveFrag");
 }
}

activity_main.xml :

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent">
 <FrameLayout
 android:id="@+id/fl_root"
 android:layout_width="match_parent"
 android:layout_height="match_parent" />
</RelativeLayout>

使用者互動頁實現

MagicTextView動畫效果

MagicTextView程式碼在文章最後展示。

我們先實現如下動畫效果

Android仿直播類app贈送禮物功能

<com.hongx.zhibo.utils.MagicTextView
 android:id="@+id/mtv_giftNum"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_centerVertical="true"
 android:layout_marginLeft="5dp"
 android:layout_toRightOf="@+id/rlparent"
 android:includeFontPadding="false"
 android:text="x1"
 android:textColor="@android:color/holo_red_dark"
 android:textSize="30sp"
 android:textStyle="bold"
 app:strokeColor="@android:color/white"
 app:strokeJoinStyle="miter"
 app:strokeWidth="2" />

動畫:

 public class NumberAnim {
 private Animator lastAnimator;
 public void showAnimator(View v) {
 if (lastAnimator != null) {
 lastAnimator.removeAllListeners();
 lastAnimator.cancel();
 lastAnimator.end();
 }
 ObjectAnimator animScaleX = ObjectAnimator.ofFloat(v,"scaleX",1.3f,1.0f);
 ObjectAnimator animScaleY = ObjectAnimator.ofFloat(v,"scaleY",1.0f);
 AnimatorSet animSet = new AnimatorSet();
 animSet.playTogether(animScaleX,animScaleY);
 animSet.setDuration(200);
 lastAnimator = animSet;
 animSet.start();
 }
 }

 mtv_giftNum.setText("x" + count);
 giftNumberAnim = new NumberAnim(); // 初始化數字動畫 
 mtv_giftNum.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 count++;
 mtv_giftNum.setText("x" + count);
 giftNumberAnim.showAnimator(mtv_giftNum);
 }
 });

禮物進入時動畫

Android仿直播類app贈送禮物功能

進入動畫設定為decelerate_interpolator減速插值器:

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
 android:duration="500"
 android:fromXDelta="-100%p"
 android:interpolator="@android:anim/decelerate_interpolator"
 android:toYDelta="0%p">
</translate>

 /**
 * 刷禮物的方法
 */
 private void showGift(String tag) {
 View newGiftView = ll_gift_group.findViewWithTag(tag);
 // 是否有該tag型別的禮物
 if (newGiftView == null) {
 // 獲取禮物
 newGiftView = getNewGiftView(tag);
 ll_gift_group.addView(newGiftView);

 // 播放動畫
 newGiftView.startAnimation(inAnim);
 final MagicTextView mtv_giftNum = newGiftView.findViewById(R.id.mtv_giftNum);
 inAnim.setAnimationListener(new Animation.AnimationListener() {

 @Override
 public void onAnimationStart(Animation animation) {
 }

 @Override
 public void onAnimationRepeat(Animation animation) {
 }

 @Override
 public void onAnimationEnd(Animation animation) {
 giftNumberAnim.showAnimator(mtv_giftNum);
 }
 });
 } else {
 // 如果列表中已經有了該型別的禮物,則不再新建,直接拿出
 // 更新標識,記錄最新修改的時間,用於回收判斷
 ImageView iv_gift = newGiftView.findViewById(R.id.iv_gift);
 iv_gift.setTag(System.currentTimeMillis());

 // 更新標識,更新記錄禮物個數
 MagicTextView mtv_giftNum = newGiftView.findViewById(R.id.mtv_giftNum);
 int giftCount = (int) mtv_giftNum.getTag() + 1; // 遞增
 mtv_giftNum.setText("x" + giftCount);
 mtv_giftNum.setTag(giftCount);
 giftNumberAnim.showAnimator(mtv_giftNum);
 }
 }

 /**
 * 獲取禮物
 */
 private View getNewGiftView(String tag) {

 // 新增標識,該view若在layout中存在,就不在生成(用於findViewWithTag判斷是否存在)
 View giftView = LayoutInflater.from(myContext).inflate(R.layout.item_gift,null);
 giftView.setTag(tag);

 // 新增標識,記錄生成時間,回收時用於判斷是否是最新的,回收最老的
 ImageView iv_gift = giftView.findViewById(R.id.iv_gift);
 iv_gift.setTag(System.currentTimeMillis());

 // 新增標識,記錄禮物個數
 MagicTextView mtv_giftNum = giftView.findViewById(R.id.mtv_giftNum);
 mtv_giftNum.setTag(1);
 mtv_giftNum.setText("x1");

 switch (tag) {
 case "gift01":
 iv_gift.setImageResource(GiftIcon[0]);
 break;
 case "gift02":
 iv_gift.setImageResource(GiftIcon[1]);
 break;
 case "gift03":
 iv_gift.setImageResource(GiftIcon[2]);
 break;
 case "gift04":
 iv_gift.setImageResource(GiftIcon[3]);
 break;
 }

 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
 lp.topMargin = 10;
 giftView.setLayoutParams(lp);

 return giftView;
 }

 @Override
 public void onClick(View v) {
 switch (v.getId()) {
 case R.id.btn_gift01: // 禮物1,送香皂
 showGift("gift01");
 break;
 case R.id.btn_gift02: // 禮物2,送玫瑰
 showGift("gift02");
 break;
 case R.id.btn_gift03: // 禮物3,送愛心
 showGift("gift03");
 break;
 case R.id.btn_gift04: // 禮物4,送蛋糕
 showGift("gift04");
 break;
 }
 }

禮物移出動畫

實現的效果如下:

Android仿直播類app贈送禮物功能

禮物移出時使用accelerate_interpolator加速差值器

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
 android:duration="500"
 android:fromYDelta="0%p"
 android:interpolator="@android:anim/accelerate_interpolator"
 android:toYDelta="-100%p">
</translate>

 /**
 * 移除禮物列表裡的giftView
 */
 private void removeGiftView(final int index) {
 // 移除列表,外加退出動畫
 final View removeGiftView = ll_gift_group.getChildAt(index);
 outAnim.setAnimationListener(new Animation.AnimationListener() {

 @Override
 public void onAnimationStart(Animation animation) {
 }

 @Override
 public void onAnimationRepeat(Animation animation) {
 }

 @Override
 public void onAnimationEnd(Animation animation) {
 ll_gift_group.removeViewAt(index);
 }
 });

 // 開啟動畫,因為定時原因,所以可能是在子執行緒
 getActivity().runOnUiThread(new Runnable() {
 @Override
 public void run() {
 removeGiftView.startAnimation(outAnim);
 }
 });
 }

如果顯示的禮物大於3種,就將最早的那種禮物移除:

// 是否有該tag型別的禮物
 if (newGiftView == null) {
 // 判斷禮物列表是否已經有3個了,如果有那麼刪除掉一個沒更新過的,然後再新增新進來的禮物,始終保持只有3個
 if (ll_gift_group.getChildCount() >= 3) {
 // 獲取前2個元素的最後更新時間
 View giftView01 = ll_gift_group.getChildAt(0);
 ImageView iv_gift01 = giftView01.findViewById(R.id.iv_gift);
 long lastTime1 = (long) iv_gift01.getTag();

 View giftView02 = ll_gift_group.getChildAt(1);
 ImageView iv_gift02 = giftView02.findViewById(R.id.iv_gift);
 long lastTime2 = (long) iv_gift02.getTag();

 if (lastTime1 > lastTime2) { // 如果第二個View顯示的時間比較長
 removeGiftView(1);
 } else { // 如果第一個View顯示的時間長
 removeGiftView(0);
 }
 }
...

開啟定時清理禮物列表

禮物顯示超過一定時間,自動將禮物在禮物列表中移除:

 /**
 * 定時清理禮物列表資訊
 */
 private void clearTiming() {
 Timer timer = new Timer();
 timer.schedule(new TimerTask() {

 @Override
 public void run() {
 int childCount = ll_gift_group.getChildCount();
 long nowTime = System.currentTimeMillis();
 for (int i = 0; i < childCount; i++) {

 View childView = ll_gift_group.getChildAt(i);
 ImageView iv_gift = (ImageView) childView.findViewById(R.id.iv_gift);
 long lastUpdateTime = (long) iv_gift.getTag();

 // 更新超過3秒就重新整理
 if (nowTime - lastUpdateTime >= 3000) {
 removeGiftView(i);
 }
 }
 }
 },3000);
 }

Android仿直播類app贈送禮物功能

聊天實現

Android仿直播類app贈送禮物功能

case R.id.tv_chat:// 聊天
 tv_chat.setVisibility(View.GONE);
 ll_inputparent.setVisibility(View.VISIBLE);
 ll_inputparent.requestFocus(); // 獲取焦點
 showKeyboard();
 break;
 case R.id.tv_send:// 傳送訊息
 String chatMsg = et_chat.getText().toString();
 if (!TextUtils.isEmpty(chatMsg)) {
 messageData.add("小明: " + chatMsg);
 et_chat.setText("");
 messageAdapter.NotifyAdapter(messageData);
 lv_message.setSelection(messageData.size());
 }
 hideKeyboard();
 break;

 /**
 * 顯示軟鍵盤
 */
 private void showKeyboard() {
 InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
 imm.showSoftInput(et_chat,InputMethodManager.SHOW_FORCED);
 }

 /**
 * 隱藏軟鍵盤
 */
 public void hideKeyboard() {
 InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
 imm.hideSoftInputFromWindow(et_chat.getWindowToken(),0);
 }

 view.setOnClickListener(new View.OnClickListener() {

 @Override
 public void onClick(View v) {
 if (ll_inputparent.getVisibility() == View.VISIBLE) {
 tv_chat.setVisibility(View.VISIBLE);
 ll_inputparent.setVisibility(View.GONE);
 hideKeyboard();
 }
 }
 });

 // 軟鍵盤監聽
 SoftKeyBoardListener.setListener(getActivity(),new SoftKeyBoardListener.OnSoftKeyBoardChangeListener() {
 @Override
 public void keyBoardShow(int height) {/*軟鍵盤顯示:執行隱藏title動畫,並修改listview高度和裝載禮物容器的高度*/

 // 輸入文字時的介面退出動畫
 AnimatorSet animatorSetHide = new AnimatorSet();
 ObjectAnimator leftOutAnim = ObjectAnimator.ofFloat(rl_num,"translationX",-rl_num.getWidth());
 ObjectAnimator topOutAnim = ObjectAnimator.ofFloat(ll_anchor,"translationY",-ll_anchor.getHeight());
 animatorSetHide.playTogether(leftOutAnim,topOutAnim);
 animatorSetHide.setDuration(300);
 animatorSetHide.start();
 // 改變listview的高度
 dynamicChangeListviewH(90);
 dynamicChangeGiftParentH(true);
 }

 @Override
 public void keyBoardHide(int height) {/*軟鍵盤隱藏:隱藏聊天輸入框並顯示聊天按鈕,執行顯示title動畫,並修改listview高度和裝載禮物容器的高度*/
 tv_chat.setVisibility(View.VISIBLE);
 ll_inputparent.setVisibility(View.GONE);
 // 輸入文字時的介面進入時的動畫
 AnimatorSet animatorSetShow = new AnimatorSet();
 ObjectAnimator leftInAnim = ObjectAnimator.ofFloat(rl_num,-rl_num.getWidth(),0);
 ObjectAnimator topInAnim = ObjectAnimator.ofFloat(ll_anchor,-ll_anchor.getHeight(),0);
 animatorSetShow.playTogether(leftInAnim,topInAnim);
 animatorSetShow.setDuration(300);
 animatorSetShow.start();

 // 改變listview的高度
 dynamicChangeListviewH(150);
 dynamicChangeGiftParentH(false);
 }
 });

 /**
 * 動態的修改listview的高度
 */
 private void dynamicChangeListviewH(int heightPX) {
 ViewGroup.LayoutParams layoutParams = lv_message.getLayoutParams();
 layoutParams.height = DisplayUtil.dip2px(getActivity(),heightPX);
 lv_message.setLayoutParams(layoutParams);
 }

 /**
 * 動態修改禮物父佈局的高度
 */
 private void dynamicChangeGiftParentH(boolean showhide) {
 if (showhide) {// 如果軟鍵盤顯示中
 if (ll_gift_group.getChildCount() != 0) {

 // 判斷是否有禮物顯示,如果有就修改父佈局高度,如果沒有就不作任何操作
 ViewGroup.LayoutParams layoutParams = ll_gift_group.getLayoutParams();
 layoutParams.height = ll_gift_group.getChildAt(0).getHeight();
 ll_gift_group.setLayoutParams(layoutParams);
 }
 } else {
 // 如果軟鍵盤隱藏中
 // 就將裝載禮物的容器的高度設定為包裹內容
 ViewGroup.LayoutParams layoutParams = ll_gift_group.getLayoutParams();
 layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
 ll_gift_group.setLayoutParams(layoutParams);
 }
 }

MagicTextView程式碼

/**
 * 該自定義view是用於顯示禮物數字的,加了些效果,內發光,陰影等
 */
public class MagicTextView extends TextView {
 private ArrayList<Shadow> outerShadows;
 private ArrayList<Shadow> innerShadows;
 private WeakHashMap<String,Pair<Canvas,Bitmap>> canvasStore;
 private Canvas tempCanvas;
 private Bitmap tempBitmap;
 private Drawable foregroundDrawable;
 private float strokeWidth;
 private Integer strokeColor;
 private Join strokeJoin;
 private float strokeMiter;
 private int[] lockedCompoundPadding;
 private boolean frozen = false;
 public MagicTextView(Context context) {
 super(context);
 init(null);
 }
 public MagicTextView(Context context,AttributeSet attrs) {
 super(context,attrs);
 init(attrs);
 }
 public MagicTextView(Context context,AttributeSet attrs,int defStyle) {
 super(context,attrs,defStyle);
 init(attrs);
 }
 public void init(AttributeSet attrs) {
 outerShadows = new ArrayList<Shadow>();
 innerShadows = new ArrayList<Shadow>();
 if (canvasStore == null) {
 canvasStore = new WeakHashMap<String,Bitmap>>();
 }
 if (attrs != null) {
 TypedArray a = getContext().obtainStyledAttributes(attrs,R.styleable.MagicTextView);
 String typefaceName = a.getString(R.styleable.MagicTextView_typeface);
 if (typefaceName != null) {
 Typeface tf = Typeface.createFromAsset(getContext().getAssets(),String.format("fonts/%s.ttf",typefaceName));
 setTypeface(tf);
 }
 if (a.hasValue(R.styleable.MagicTextView_foreground)) {
 Drawable foreground = a.getDrawable(R.styleable.MagicTextView_foreground);
 if (foreground != null) {
 this.setForegroundDrawable(foreground);
 } else {
 this.setTextColor(a.getColor(R.styleable.MagicTextView_foreground,0xff000000));
 }
 }
 if (a.hasValue(R.styleable.MagicTextView_innerShadowColor)) {
 this.addInnerShadow(a.getFloat(R.styleable.MagicTextView_innerShadowRadius,0),a.getFloat(R.styleable.MagicTextView_innerShadowDx,a.getFloat(R.styleable.MagicTextView_innerShadowDy,a.getColor(R.styleable.MagicTextView_innerShadowColor,0xff000000));
 }
 if (a.hasValue(R.styleable.MagicTextView_outerShadowColor)) {
 this.addOuterShadow(a.getFloat(R.styleable.MagicTextView_outerShadowRadius,a.getFloat(R.styleable.MagicTextView_outerShadowDx,a.getFloat(R.styleable.MagicTextView_outerShadowDy,a.getColor(R.styleable.MagicTextView_outerShadowColor,0xff000000));
 }
 if (a.hasValue(R.styleable.MagicTextView_strokeColor)) {
 float strokeWidth = a.getFloat(R.styleable.MagicTextView_strokeWidth,1);
 int strokeColor = a.getColor(R.styleable.MagicTextView_strokeColor,0xff000000);
 float strokeMiter = a.getFloat(R.styleable.MagicTextView_strokeMiter,10);
 Join strokeJoin = null;
 switch (a.getInt(R.styleable.MagicTextView_strokeJoinStyle,0)) {
 case (0):
 strokeJoin = Join.MITER;
 break;
 case (1):
 strokeJoin = Join.BEVEL;
 break;
 case (2):
 strokeJoin = Join.ROUND;
 break;
 }
 this.setStroke(strokeWidth,strokeColor,strokeJoin,strokeMiter);
 }
 }
 }
 public void setStroke(float width,int color,Join join,float miter) {
 strokeWidth = width;
 strokeColor = color;
 strokeJoin = join;
 strokeMiter = miter;
 }
 public void setStroke(float width,int color) {
 setStroke(width,color,Join.MITER,10);
 }
 public void addOuterShadow(float r,float dx,float dy,int color) {
 if (r == 0) {
 r = 0.0001f;
 }
 outerShadows.add(new Shadow(r,dx,dy,color));
 }
 public void addInnerShadow(float r,int color) {
 if (r == 0) {
 r = 0.0001f;
 }
 innerShadows.add(new Shadow(r,color));
 }
 public void clearInnerShadows() {
 innerShadows.clear();
 }
 public void clearOuterShadows() {
 outerShadows.clear();
 }
 public void setForegroundDrawable(Drawable d) {
 this.foregroundDrawable = d;
 }
 public Drawable getForeground() {
 return this.foregroundDrawable == null ? this.foregroundDrawable : new ColorDrawable(this.getCurrentTextColor());
 }
 @Override
 public void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 freeze();
 Drawable restoreBackground = this.getBackground();
 Drawable[] restoreDrawables = this.getCompoundDrawables();
 int restoreColor = this.getCurrentTextColor();
 this.setCompoundDrawables(null,null,null);
 for (Shadow shadow : outerShadows) {
 this.setShadowLayer(shadow.r,shadow.dx,shadow.dy,shadow.color);
 super.onDraw(canvas);
 }
 this.setShadowLayer(0,0);
 this.setTextColor(restoreColor);
 if (this.foregroundDrawable != null && this.foregroundDrawable instanceof BitmapDrawable) {
 generateTempCanvas();
 super.onDraw(tempCanvas);
 Paint paint = ((BitmapDrawable) this.foregroundDrawable).getPaint();
 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
 this.foregroundDrawable.setBounds(canvas.getClipBounds());
 this.foregroundDrawable.draw(tempCanvas);
 canvas.drawBitmap(tempBitmap,null);
 tempCanvas.drawColor(Color.TRANSPARENT,PorterDuff.Mode.CLEAR);
 }
 if (strokeColor != null) {
 TextPaint paint = this.getPaint();
// paint.setTextAlign(Paint.Align.CENTER);
 paint.setStyle(Style.STROKE);
 paint.setStrokeJoin(strokeJoin);
 paint.setStrokeMiter(strokeMiter);
 this.setTextColor(strokeColor);
 paint.setStrokeWidth(strokeWidth);
 super.onDraw(canvas);
 paint.setStyle(Style.FILL);
 this.setTextColor(restoreColor);
 }
 if (innerShadows.size() > 0) {
 generateTempCanvas();
 TextPaint paint = this.getPaint();
 for (Shadow shadow : innerShadows) {
 this.setTextColor(shadow.color);
 super.onDraw(tempCanvas);
 this.setTextColor(0xFF000000);
 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
 paint.setMaskFilter(new BlurMaskFilter(shadow.r,BlurMaskFilter.Blur.NORMAL));
 tempCanvas.save();
 tempCanvas.translate(shadow.dx,shadow.dy);
 super.onDraw(tempCanvas);
 tempCanvas.restore();
 canvas.drawBitmap(tempBitmap,PorterDuff.Mode.CLEAR);
 paint.setXfermode(null);
 paint.setMaskFilter(null);
 this.setTextColor(restoreColor);
 this.setShadowLayer(0,0);
 }
 }
 if (restoreDrawables != null) {
 this.setCompoundDrawablesWithIntrinsicBounds(restoreDrawables[0],restoreDrawables[1],restoreDrawables[2],restoreDrawables[3]);
 }
 this.setBackgroundDrawable(restoreBackground);
 this.setTextColor(restoreColor);
 unfreeze();
 }
 private void generateTempCanvas() {
 String key = String.format("%dx%d",getWidth(),getHeight());
 Pair<Canvas,Bitmap> stored = canvasStore.get(key);
 if (stored != null) {
 tempCanvas = stored.first;
 tempBitmap = stored.second;
 } else {
 tempCanvas = new Canvas();
 tempBitmap = Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_8888);
 tempCanvas.setBitmap(tempBitmap);
 canvasStore.put(key,new Pair<Canvas,Bitmap>(tempCanvas,tempBitmap));
 }
 }
 public void freeze() {
 lockedCompoundPadding = new int[]{
 getCompoundPaddingLeft(),getCompoundPaddingRight(),getCompoundPaddingTop(),getCompoundPaddingBottom()
 };
 frozen = true;
 }
 public void unfreeze() {
 frozen = false;
 }
 @Override
 public void requestLayout() {
 if (!frozen) super.requestLayout();
 }
 @Override
 public void postInvalidate() {
 if (!frozen) super.postInvalidate();
 }
 @Override
 public void postInvalidate(int left,int top,int right,int bottom) {
 if (!frozen) super.postInvalidate(left,top,right,bottom);
 }
 @Override
 public void invalidate() {
 if (!frozen) super.invalidate();
 }
 @Override
 public void invalidate(Rect rect) {
 if (!frozen) super.invalidate(rect);
 }
 @Override
 public void invalidate(int l,int t,int r,int b) {
 if (!frozen) super.invalidate(l,t,r,b);
 }
 @Override
 public int getCompoundPaddingLeft() {
 return !frozen ? super.getCompoundPaddingLeft() : lockedCompoundPadding[0];
 }
 @Override
 public int getCompoundPaddingRight() {
 return !frozen ? super.getCompoundPaddingRight() : lockedCompoundPadding[1];
 }
 @Override
 public int getCompoundPaddingTop() {
 return !frozen ? super.getCompoundPaddingTop() : lockedCompoundPadding[2];
 }
 @Override
 public int getCompoundPaddingBottom() {
 return !frozen ? super.getCompoundPaddingBottom() : lockedCompoundPadding[3];
 }
 public static class Shadow {
 float r;
 float dx;
 float dy;
 int color;

 public Shadow(float r,int color) {
 this.r = r;
 this.dx = dx;
 this.dy = dy;
 this.color = color;
 }
 }
}

Github:https://github.com/345166018/AndroidUI/tree/master/HxZhibo

總結

以上所述是小編給大家介紹的Android仿直播類app贈送禮物功能,希望對大家有所幫助!