android机顶盒 EPG View实现方法

        最近需要改进PEG View的响应速度,因为我们目前的框架是采用动态创建TextView的方法,导致上下左右切换时响应没有那么快,老板很不高兴,作为员工那必须得改进啊。经过一段时间的查找,终于有了如下的EPG View,速度极快。

  1、自定义EPG View,代码如下:

package com.amlogic.dvb_custom_view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;

import com.amlogic.DVBPlayer.AndroidNineMainMenu;
import com.amlogic.DVBPlayer.R;
import com.amlogic.aidl.ServiceInfoEntity;
import com.amlogic.dvb_interface.EPGData;

import com.amlogic.dvb_util.EPGUtil;
import com.nes.gracenote.bean.EnhancedScheduleGridBean;

import org.joda.time.DateTime;
import org.joda.time.LocalDateTime;

import java.util.Calendar;
import java.util.List;

public class EpgView extends ViewGroup {
    public static int DAYS_BACK_MILLIS;
    public static final int DAYS_FORWARD_MILLIS = 5 * 24 * 60 * 60 * 1000;
    private static int HOURS_IN_VIEWPORT_MILLIS = 2 * 60 * 60 * 1000;
    private static final int TIME_LABEL_SPACING_MILLIS = 30 * 60 * 1000;
    public static final int UP_DIRECTION = 0;
    public static final int DOWN_DIRECTION = 1;

    private Context contextObj;
    private boolean mEventNeedSelectedStatus = false;

    private final Rect mClipRect;
    private final Rect mDrawingRect;
    private final Rect mMeasuringRect;
    private final Paint mPaint;
    private final Scroller mScroller;

    private int mChannelLayoutPadding;
    private int mChannelLayoutHeight;
    private int mChannelLayoutWidth;
    private final int mChannelLayoutMargin;
    private final int mChannelLayoutBackground;
    private final int mRedColor;
    private final int mColorPrimaryDark;
    private final int mTimerBarBackground;

    private final int mEventLayoutSelected;
    private final int mEventLayoutBackground;
    private final int mEventLayoutBackgroundCurrent;
    private final int mEventLayoutTextColor;
    public int mEventLayoutTextSize;

    private final int mTimeBarLineWidth;
    private final int mTimeBarLineColor;
    private int mTimeBarHeight;
    private int mTimeBarTextSize;

    private final int mEPGBackground;
    //private final Map<String, Bitmap> mChannelImageCache;
    //private final Map<String, Target> mChannelImageTargetCache;

    private int mMaxHorizontalScroll;
    private int mMaxVerticalScroll;

    //event显示区域(2个小时)里,每一个像素占的毫秒数
    private long mMillisPerPixel;

    //时刻表上最左边的那个时间,单位毫秒
    private long mTimeOffset;


    private long mTimeLowerBoundary;
    private long mTimeUpperBoundary;

    public EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean currentProgram = null;
    private boolean drawCurrentTimeLine = false;
    public int currentChannelPosition = -1;

    private int cuDays = 0;
    private boolean isMoveRight;
    private boolean isMoveLeft;

    private EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean referenceEvent;
    private int referenceEventPosition;

    private EPGData epgData = null;
    private List<ServiceInfoEntity> serviceList;


    public EpgView(Context context) {
        this(context, null);
    }

    public EpgView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public EpgView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        DAYS_BACK_MILLIS = 0;
        contextObj = context;

        if (cuDays > 0) {
            DAYS_BACK_MILLIS = cuDays * 24 * 60 * 60 * 1000;
        } else {
            DAYS_BACK_MILLIS = 0;
        }

        setWillNotDraw(false);

        //resetBoundaries();

        mDrawingRect = new Rect();
        mClipRect = new Rect();
        mMeasuringRect = new Rect();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        //mChannelImageCache = Maps.newHashMap();
        //mChannelImageTargetCache = Maps.newHashMap();

        // Adding some friction that makes the epg less flappy.
        mScroller = new Scroller(context);
        mScroller.setFriction(ViewConfiguration.getScrollFriction());

        mEPGBackground = getResources().getColor(R.color.epg_background);
        mChannelLayoutMargin = getResources().getDimensionPixelSize(R.dimen.epg_channel_layout_margin_8);
        mChannelLayoutPadding = getResources().getDimensionPixelSize(R.dimen.epg_channel_layout_padding_8);
        mChannelLayoutHeight = getResources().getDimensionPixelSize(R.dimen.epg_channel_layout_height_8);
        mChannelLayoutWidth = getResources().getDimensionPixelSize(R.dimen.epg_channel_layout_width);
        mChannelLayoutBackground = getResources().getColor(R.color.epg_channel_layout_background);
        mEventLayoutBackground = getResources().getColor(R.color.translucent_black);
        mEventLayoutBackgroundCurrent = getResources().getColor(R.color.epg_background_black);
        mEventLayoutTextColor = getResources().getColor(R.color.epg_event_layout_text);
        mEventLayoutSelected = getResources().getColor(R.color.epg_date_title_color);
        mEventLayoutTextSize = getResources().getDimensionPixelSize(R.dimen.epg_event_layout_text_8);
        mTimeBarHeight = getResources().getDimensionPixelSize(R.dimen.epg_time_bar_height_8);
        mTimeBarTextSize = getResources().getDimensionPixelSize(R.dimen.epg_time_bar_text_8);
        mTimeBarLineWidth = getResources().getDimensionPixelSize(R.dimen.epg_time_bar_line_width_8);
        mTimeBarLineColor = getResources().getColor(R.color.mainmenu_epg_time_bar);
        mRedColor = getResources().getColor(R.color.colorAccent);
        mColorPrimaryDark = getResources().getColor(R.color.colorPrimaryDark);
        mTimerBarBackground = getResources().getColor(R.color.color_epg_focus);
    }

    /*<dimen name="epg_channel_layout_margin_8">1dp</dimen> <!--EPG 每一行的间隔距离-->
      <dimen name="epg_channel_layout_padding_8">5dp</dimen> <!-- epg event里的文字和边框的间隔-->
      <dimen name="epg_channel_layout_height_8">50dp</dimen>
      <dimen name="epg_channel_layout_width_8">165dp</dimen>
      <dimen name="epg_channel_layout_width">0dp</dimen>
      <dimen name="epg_event_layout_text_8">15dp</dimen> <!-- epg event里的文字大小-->
      <dimen name="epg_time_bar_height_8">30dp</dimen>
      <dimen name="epg_time_bar_height">40dp</dimen>
      <dimen name="epg_time_bar_text_8">15dp</dimen>
      <dimen name="epg_time_bar_line_width_8">1dp</dimen> <!-- epg 时间竖线粗-->*/

    /*<!--整个epg 区域的背景色-->
      <color name="epg_background">#ff4A4A4A</color>
      <color name="epg_background_white">#ffffffff</color>
      <!--epg event背景颜色-->
      <color name="epg_background_black">#ff000000</color>
      <color name="epg_event_layout_selected">#4772a4</color>
      <color name="epg_channel_layout_background">#ff323232</color>
      <color name="epg_event_layout_text">#ffd6d6d6</color>
      <color name="epg_logo_background">#ff9a9a9a</color>
      <color name="mainmenu_epg_time_bar">#ffc57120</color>
      <color name="translucent_black">#E6000000</color>
      <color name="epg_line_data_background">#D91c1c1c</color> */

    public void setEPGData(Context context, EPGData epgData) {
        this.epgData = epgData;
        serviceList = epgData.getChannels();

        contextObj = context;

        Log.d("wujiang", "EpgView: setEPGData->serviceList size = " + serviceList.size());

        if (serviceList.size() == 0) {
            return;
        }

        currentChannelPosition = getFirstVisibleChannelPosition();
        //Log.d("wujiang", "EpgView: currentChannelPosition = " + currentChannelPosition);
        int programPosition = getProgramPosition(currentChannelPosition, Calendar.getInstance().getTimeInMillis());
        currentProgram = epgData.getEvent(currentChannelPosition, programPosition);

        //Log.d("wujiang", "setEPGData: Calendar.getInstance().getTimeInMillis() = " + Calendar.getInstance().getTimeInMillis());
        Log.d("wujiang", "setEPGData: programPosition = " + programPosition);

        Log.d("wujiang", "setEPGData: channel name = " + serviceList.get(currentChannelPosition).getName());

        if (currentProgram == null) {
            Log.d("wujiang", "setEPGData: currentProgram == null");
        }

        //暂时不设置被选中的event
        //if (currentProgram != null) {
        //    currentProgram.setSelected(true);
        //}

        referenceEventPosition = programPosition;
        //Log.e(TAG, " * * * EPG setEPGData() (referenceEventPosition) " + referenceEventPosition);
        referenceEvent = currentProgram;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

    }

    @Override
    protected void onDraw(Canvas canvas) {
        //super.onDraw(canvas);
        if (epgData != null && epgData.hasData()) {
            mTimeLowerBoundary = getTimeFrom(getScrollX());
            mTimeUpperBoundary = getTimeFrom(getScrollX() + getWidth());
            //Log.e("M_TIME_UPPER",  new Date(mTimeUpperBoundary).toString());

            Rect drawingRect = mDrawingRect;
            drawingRect.left = getScrollX();
            drawingRect.top = getScrollY();
            drawingRect.right = drawingRect.left + getWidth();
            drawingRect.bottom = drawingRect.top + getHeight();

            //drawChannelListItems(canvas, drawingRect);
            drawEvents(canvas, drawingRect);
            drawTimebar(canvas, drawingRect);
            drawTimeLine(canvas, drawingRect);

            //drawResetButton(canvas, drawingRect);

            // If scroller is scrolling/animating do scroll. This applies when doing a fling.
            if (mScroller.computeScrollOffset()) {
                scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            }
        } else {
            mTimeLowerBoundary = getTimeFrom(getScrollX());
            mTimeUpperBoundary = getTimeFrom(getScrollX() + getWidth());

            Rect drawingRect = mDrawingRect;
            drawingRect.left = getScrollX();
            drawingRect.top = getScrollY();
            drawingRect.right = drawingRect.left + getWidth();
            drawingRect.bottom = drawingRect.top + getHeight();

            drawBlankEvents(canvas, drawingRect);
            drawTimebar(canvas, drawingRect);
        }
    }

    /**
     * This will recalculate boundaries, maximal scroll and scroll to start position which is current time.
     * To be used on device rotation etc since the device height and width will change.
     *
     * @param withAnimation true if scroll to current position should be animated.
     */
    public void recalculateAndRedraw(boolean withAnimation, boolean needDrawSelectedProgram) {
        if (epgData != null && epgData.hasData()) {
            Log.d("wujiang", "recalculateAndRedraw: needDrawSelectedProgram = " + needDrawSelectedProgram);
            mEventNeedSelectedStatus = needDrawSelectedProgram;
            resetBoundaries();
            calculateMaxVerticalScroll();
            calculateMaxHorizontalScroll();

            mScroller.startScroll(getScrollX(), getScrollY(), getXPositionStart() - getScrollX(), 0, withAnimation ? 0 : 0);

            if (currentProgram == null) {
                Log.d("wujiang", "recalculateAndRedraw: 11111111111");
                if (needDrawSelectedProgram == false) {
                    referenceEvent = gotoProgramNotSelect(currentChannelPosition, Calendar.getInstance().getTimeInMillis());
                } else {
                    referenceEvent = gotoProgram(currentChannelPosition, Calendar.getInstance().getTimeInMillis());
                }
            } else {
                Log.d("wujiang", "recalculateAndRedraw: 2222222222");
                if ((currentProgram.getIntStartTime() > EPGUtil.getCurrentTimeInMillis()) || (currentProgram.getIntStartTime() < EPGUtil.getCurrentTimeInMillis())) {
                    int progPos = getProgramPosition(currentChannelPosition, EPGUtil.getCurrentTimeInMillis());
                    Log.d("wujiang", "recalculateAndRedraw: progPos = " + progPos);
                    EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean event = epgData.getEvent(currentChannelPosition, progPos);
                    if (needDrawSelectedProgram == false) {
                        referenceEvent = gotoProgramNotSelect(currentChannelPosition, event.getIntStartTime());
                    } else {
                        referenceEvent = gotoProgram(currentChannelPosition, event.getIntStartTime());
                    }
                }
            }
            redraw();
        } else {
            Log.d("wujiang", "recalculateAndRedraw: epgData == null || !epgData.hasData()");
            resetBoundaries();
            redraw();
        }
    }

    public void redraw() {
        Log.d("wujiang", "redraw: call this fun");
        invalidate();
        requestLayout();
    }

    private EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean gotoProgram(int channelPosition, long time) {
        Log.d("wujiang", "gotoProgram: call this fun, channelPosition = " + channelPosition);
        if (channelPosition > -1 && channelPosition < epgData.getChannelCount()) {
            int programPosition = getProgramPosition(channelPosition, time);

            //Log.d("wujiang", "gotoProgram: programPosition = " + programPosition);

            if (programPosition != -1) {
                //Log.d("wujiang", "gotoProgram: 111111111111");
                epgData.cleanSelection();
                EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean event = epgData.getEvent(channelPosition, programPosition);
                event.setSelected(true);
                currentProgram = event;
                /*if (epgActivity != null) {
                    //epgActivity.loadEventPosterFromServer(currentProgram);
                    update(currentProgram);
                } else {
                    Log.e(TAG, "NULLLLLLLLLLLLLLLLLLL");
                }*/
                currentChannelPosition = channelPosition;
                if (isMoveLeft || isMoveRight) {
                    referenceEvent = event;
                } else {
                    referenceEventPosition = programPosition;
                }

                ((AndroidNineMainMenu)contextObj).showEpgDetailInfo(currentProgram);
                return event;
            } else {
                //Log.d("wujiang", "gotoProgram: 222222222222");
                //没有EPG信息
                EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean event = new EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean();
                epgData.cleanSelection();

                event.setTitle("No Information");
                event.setIntStartTime(mTimeLowerBoundary);
                event.setIntStopTime(mTimeUpperBoundary);
                //Log.d("wujiang", "gotoProgram: mTimeLowerBoundary = " + mTimeLowerBoundary);
                //Log.d("wujiang", "gotoProgram: mTimeUpperBoundary = " + mTimeUpperBoundary);
                event.setSelected(true);
                currentProgram = event;
                currentChannelPosition = channelPosition;
                if (isMoveLeft || isMoveRight) {
                    referenceEvent = event;
                } else {
                    referenceEventPosition = programPosition;
                }

                ((AndroidNineMainMenu)contextObj).showEpgDetailInfo(currentProgram);
                return event;
            }
        }

        return null;
    }

    private EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean gotoProgramNotSelect(int channelPosition, long time) {
        Log.d("wujiang", "gotoProgramNotSelect: call this fun, channelPosition = " + channelPosition);
        if (channelPosition > -1 && channelPosition < epgData.getChannelCount()) {
            int programPosition = getProgramPosition(channelPosition, time);

            Log.d("wujiang", "gotoProgramNotSelect: programPosition = " + programPosition);

            if (programPosition != -1) {
                epgData.cleanSelection();
                EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean event = epgData.getEvent(channelPosition, programPosition);
                //event.setSelected(true);
                currentProgram = event;
                /*if (epgActivity != null) {
                    //epgActivity.loadEventPosterFromServer(currentProgram);
                    update(currentProgram);
                } else {
                    Log.e(TAG, "NULLLLLLLLLLLLLLLLLLL");
                }*/
                currentChannelPosition = channelPosition;
                if (isMoveLeft || isMoveRight) {
                    referenceEvent = event;
                } else {
                    referenceEventPosition = programPosition;
                }
                return event;
            }
        }

        return null;
    }

    private int getProgramPosition(int channelPosition, long time) {
        List<EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean> events = epgData.getEvents(channelPosition);
        Log.d("wujiang", "getProgramPosition: events size = " + events.size());
        //Log.d("wujiang", "getProgramPosition: time = " + time);

        if (events != null) {
            for (int eventPos = 0; eventPos < events.size(); eventPos++) {
                EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean event = events.get(eventPos);
                //Log.d("wujiang", "getProgramPosition: event getIntStartTime = " + event.getIntStartTime());
                //Log.d("wujiang", "getProgramPosition: event getIntStopTime = " + event.getIntStopTime());

                if ((event.getIntStartTime()) <= time && ((event.getIntStopTime()) > time)) {
                    return eventPos;
                }
            }
        }
        return -1;
    }

    private void calculateMaxVerticalScroll() {
        final int maxVerticalScroll = getTopFrom(epgData.getChannelCount() - 2) + mChannelLayoutHeight;
        mMaxVerticalScroll = maxVerticalScroll < getHeight() ? 0 : maxVerticalScroll - getHeight();
    }

    private void calculateMaxHorizontalScroll() {
        long currentFWDMillis = ((LocalDateTime.now().toDateTime().getMillis() + HOURS_IN_VIEWPORT_MILLIS));
        mMaxHorizontalScroll = (int) (mChannelLayoutMargin + mChannelLayoutWidth + (DAYS_BACK_MILLIS + EPGUtil.roundOfTimeToLowerBound(LocalDateTime.now().toDateTime().getMillis()) + HOURS_IN_VIEWPORT_MILLIS + ((LocalDateTime.now().toDateTime().withTime(23, 59, 59, 999).getMillis())) + DAYS_FORWARD_MILLIS) / mMillisPerPixel);
    }

    private void drawTimeLine(Canvas canvas, Rect drawingRect) {
        //long now = System.currentTimeMillis();
        long now = EPGUtil.getCurrentTimeInMillis();

        if (shouldDrawTimeLine(now)) {
            drawingRect.left = getXFrom(now);
            drawingRect.top = getScrollY();
            drawingRect.right = drawingRect.left + mTimeBarLineWidth;
            drawingRect.bottom = drawingRect.top + mTimeBarHeight;
            mPaint.setColor(mTimeBarLineColor);
            canvas.drawRect(drawingRect, mPaint);
        }
    }

    private boolean shouldDrawTimeLine(long now) {
        return now >= mTimeLowerBoundary && now < mTimeUpperBoundary;
    }

    private void drawTimebar(Canvas canvas, Rect drawingRect) {
        //drawingRect.left = getScrollX() + mChannelLayoutWidth + mChannelLayoutMargin;
        drawingRect.left = getScrollX() + mChannelLayoutWidth;
        drawingRect.top = getScrollY();
        drawingRect.right = drawingRect.left + getWidth();
        drawingRect.bottom = drawingRect.top + mTimeBarHeight;

        //Log.d("wujiang", "drawTimebar: getScrollX = " + getScrollX());
        //Log.d("wujiang", "drawTimebar: drawingRect.left = " + drawingRect.left);

        //mClipRect.left = getScrollX() + mChannelLayoutWidth + mChannelLayoutMargin;
        mClipRect.left = getScrollX() + mChannelLayoutWidth;
        mClipRect.top = getScrollY();
        mClipRect.right = drawingRect.left + getWidth();//getScrollX() + getWidth();
        mClipRect.bottom = mClipRect.top + mTimeBarHeight;

        //Log.d("wujiang", "drawTimebar: mClipRect.left = " + mClipRect.left);

        canvas.save();
        canvas.clipRect(mClipRect);

        // Background
        mPaint.setColor(mTimerBarBackground);
        canvas.drawRect(drawingRect, mPaint);

        // Time stamps
        mPaint.setColor(mEventLayoutTextColor);
        mPaint.setTextSize(mTimeBarTextSize);

        for (int i = 0; i < HOURS_IN_VIEWPORT_MILLIS / TIME_LABEL_SPACING_MILLIS; i++) {
            // Get time and round to nearest half hour
            final long time = TIME_LABEL_SPACING_MILLIS *
                    (((mTimeLowerBoundary + (TIME_LABEL_SPACING_MILLIS * i)) +
                            (TIME_LABEL_SPACING_MILLIS / 2)) / TIME_LABEL_SPACING_MILLIS);

            mPaint.setColor(mEventLayoutTextColor);

            canvas.drawText(EPGUtil.getShortTime(time), getXFrom(time),
                    drawingRect.top + (((drawingRect.bottom - drawingRect.top) / 2) + (mTimeBarTextSize / 2)), mPaint);

//                  mPaint.setColor(mEPGBackground);
//                  canvas.drawLine(getXFrom(time), drawingRect.top, getXFrom(time), drawingRect.bottom, mPaint);
        }

        canvas.restore();
        //drawTimebarDayIndicator(canvas, drawingRect);
        drawTime();
        drawTimebarBottomStroke(canvas, drawingRect);
    }

    private void drawTime() {
        ((AndroidNineMainMenu) contextObj).setEpgDateTextViewString(EPGUtil.getWeekdayName(mTimeLowerBoundary));
    }

    private void drawTimebarDayIndicator(Canvas canvas, Rect drawingRect) {
        drawingRect.left = getScrollX();
        drawingRect.top = getScrollY();
        drawingRect.right = drawingRect.left + mChannelLayoutWidth;
        drawingRect.bottom = drawingRect.top + mTimeBarHeight;

        // Background
        mPaint.setColor(mChannelLayoutBackground);
        canvas.drawRect(drawingRect, mPaint);

        // Text
        mPaint.setColor(mEventLayoutTextColor);
        mPaint.setTextSize(mTimeBarTextSize);
        mPaint.setTextAlign(Paint.Align.CENTER);

        if (EPGUtil.getWeekdayName(mTimeLowerBoundary).equals("Today")) {
            canvas.drawText(EPGUtil.getWeekdayName(mTimeLowerBoundary),
                    drawingRect.left + ((drawingRect.right - drawingRect.left) / 2),
                    drawingRect.top + (((drawingRect.bottom - drawingRect.top) / 2) + (mTimeBarTextSize / 2)), mPaint);
        } else {
            // java.lang.ArrayIndexOutOfBoundsException: length=1; index=1  canvas.drawText(tmpStr[1],
            String tmpStr[] = EPGUtil.getWeekdayName(mTimeLowerBoundary).split("\n");
            canvas.drawText(tmpStr[0],
                    drawingRect.left + ((drawingRect.right - drawingRect.left) / 2),
                    drawingRect.top + (((drawingRect.bottom - drawingRect.top) / 4)) + (mTimeBarTextSize / 2), mPaint);

            canvas.drawText(tmpStr[1],
                    drawingRect.left + ((drawingRect.right - drawingRect.left) / 2),
                    drawingRect.top + (((drawingRect.bottom - drawingRect.top) / 2) + (mTimeBarTextSize)), mPaint);
            tmpStr = null;
        }
        mPaint.setTextAlign(Paint.Align.LEFT);
    }

    private void drawTimebarBottomStroke(Canvas canvas, Rect drawingRect) {
        drawingRect.left = getScrollX();
        drawingRect.top = getScrollY() + mTimeBarHeight;
        drawingRect.right = drawingRect.left + getWidth();
        drawingRect.bottom = drawingRect.top + mChannelLayoutMargin;
        // Bottom stroke
        mPaint.setColor(mEPGBackground);
        canvas.drawRect(drawingRect, mPaint);
    }

    private void drawChannelListItems(Canvas canvas, Rect drawingRect) {
        //Log.d("wujiang", "drawChannelListItems: call this fun");
        mMeasuringRect.left = getScrollX();
        mMeasuringRect.top = getScrollY();
        mMeasuringRect.right = drawingRect.left + mChannelLayoutWidth;
        mMeasuringRect.bottom = mMeasuringRect.top + getHeight();

        final int firstPos = getFirstVisibleChannelPosition();
        final int lastPos = getLastVisibleChannelPosition();

        for (int pos = firstPos; pos <= lastPos; pos++) {
            drawChannelItem(canvas, pos, drawingRect);
        }
    }

    private void drawEvents(Canvas canvas, Rect drawingRect) {
        //Log.d("wujiang", "drawEvents: call this fun");
        final int firstPos = getFirstVisibleChannelPosition();
        final int lastPos = getLastVisibleChannelPosition();

        for (int pos = firstPos; pos <= lastPos; pos++) {
            // Set clip rectangle
            mClipRect.left = getScrollX() + mChannelLayoutWidth + mChannelLayoutMargin;
            mClipRect.top = getTopFrom(pos);
            mClipRect.right = getScrollX() + getWidth();
            mClipRect.bottom = mClipRect.top + mChannelLayoutHeight;

            canvas.save();
            canvas.clipRect(mClipRect);

            // Draw each event
            boolean foundFirst = false;

            List<EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean> epgEvents = epgData.getEvents(pos);
            //Log.d("wujiang", "drawEvents: epgEvents size = " + epgEvents.size());
            if (epgEvents.size() <= 0) {
                //该频道没有EPG信息
                //Log.d("wujiang", "drawEvents: 11111111");
                drawNoInforEvent(canvas, pos, drawingRect);
            } else {
                //Log.d("wujiang", "drawEvents: 222222222");
                for (EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean event : epgEvents) {
                    if (isEventVisible(event.getIntStartTime(), event.getIntStopTime())) {
                        //Log.d("wujiang", "drawEvents: 3333333");
                        drawEvent(canvas, pos, event, drawingRect);
                        foundFirst = true;
                    } else if (foundFirst) {
                        break;
                    }
                }

                if (foundFirst == false) {
                    //Log.d("wujiang", "drawEvents: 44444444");
                    drawNoInforEvent(canvas, pos, drawingRect);
                }
            }

            canvas.restore();
        }
    }

    private void drawBlankEvents(Canvas canvas, Rect drawingRect) {
        final int firstPos = getFirstVisibleChannelPosition();
        final int lastPos = getLastBlankLineChannelPosition();

        for (int pos = firstPos; pos <= lastPos; pos++) {
            mClipRect.left = getScrollX() + mChannelLayoutWidth + mChannelLayoutMargin;
            mClipRect.top = getTopFrom(pos);
            mClipRect.right = getScrollX() + getWidth();
            mClipRect.bottom = mClipRect.top + mChannelLayoutHeight;

            canvas.save();
            canvas.clipRect(mClipRect);

            mPaint.setColor(mEventLayoutBackground);
            canvas.drawRect(mClipRect, mPaint);

            canvas.restore();
        }
    }

    private void drawNoInforEvent(final Canvas canvas, final int channelPosition, final Rect drawingRect) {
        //Log.d("wujiang", "drawNoInforEvent: call this function");

        String title = "No Information";
        setEventDrawingRectangle(channelPosition, mTimeLowerBoundary, mTimeUpperBoundary, drawingRect, title);

        // Background
        mPaint.setColor(drawCurrentTimeLine ? mEventLayoutBackgroundCurrent : mEventLayoutBackground);

        if (currentChannelPosition == channelPosition && mEventNeedSelectedStatus == true) {
            mPaint.setColor(mEventLayoutSelected);
        }
        canvas.drawRect(drawingRect, mPaint);

        // Add left and right inner padding
        drawingRect.left += mChannelLayoutPadding;
        drawingRect.right -= mChannelLayoutPadding;

        // Text
        mPaint.setColor(mEventLayoutTextColor);
        mPaint.setTextSize(mEventLayoutTextSize);

        // Move drawing.top so text will be centered (text is drawn bottom>up)
        mPaint.getTextBounds(title, 0, title.length(), mMeasuringRect);
        drawingRect.top += (((drawingRect.bottom - drawingRect.top) / 2) + (mMeasuringRect.height() / 2));

        // Text
        if (currentChannelPosition == channelPosition && mEventNeedSelectedStatus == true) {
            mPaint.setColor(Color.YELLOW);
            mPaint.setTextSize(mEventLayoutTextSize);
        } else {
            mPaint.setColor(mEventLayoutTextColor);
            mPaint.setTextSize(mEventLayoutTextSize);
        }

        //NEW CHANGES USING SHOW_TYPE of EVENT
        title = title.substring(0, mPaint.breakText(title, true, drawingRect.right - drawingRect.left, null));

        TextPaint textPaint = new TextPaint(Paint.LINEAR_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
        textPaint.setColor(mPaint.getColor());
        textPaint.setTextSize(mPaint.getTextSize());
        textPaint.setStyle(mPaint.getStyle());

        CharSequence txt = null;
        txt = TextUtils.ellipsize(title, textPaint, (drawingRect.right - drawingRect.left) - 10, TextUtils.TruncateAt.END);
        canvas.drawText(txt, 0, txt.length(), drawingRect.left, drawingRect.top, textPaint);
    }

    private void drawEvent(final Canvas canvas, final int channelPosition, final EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean event, final Rect drawingRect) {
        setEventDrawingRectangle(channelPosition, event.getIntStartTime(), event.getIntStopTime(), drawingRect, event.getTitle());

        // Background
        mPaint.setColor(event.isCurrent() && drawCurrentTimeLine ? mEventLayoutBackgroundCurrent : mEventLayoutBackground);

        if (event.isSelected()) {
            mPaint.setColor(mEventLayoutSelected);
        }

        canvas.drawRect(drawingRect, mPaint);

        // Add left and right inner padding
        drawingRect.left += mChannelLayoutPadding;
        drawingRect.right -= mChannelLayoutPadding;

        // Text
        mPaint.setColor(mEventLayoutTextColor);
        mPaint.setTextSize(mEventLayoutTextSize);

        //Log.e("TAG", " @ @ @ @ " + event.getGenres());
        // Set Genre
        Rect genreBackgroundRect = null;
        ServiceInfoEntity serviceInfoEntity = serviceList.get(getServiceIndexInList((int) event.getChannelNumber()));

        if (genreBackgroundRect == null) {
            genreBackgroundRect = new Rect();
            genreBackgroundRect.set(drawingRect.left, drawingRect.top + mTimeBarHeight + 10, (int) (drawingRect.left), drawingRect.bottom - 5);
        }

        // Move drawing.top so text will be centered (text is drawn bottom>up)
        mPaint.getTextBounds(event.getTitle(), 0, event.getTitle().length(), mMeasuringRect);
        drawingRect.top += (((drawingRect.bottom - drawingRect.top) / 2) + (mMeasuringRect.height() / 2));
        // Text
        if (event.isSelected()) {
            mPaint.setColor(Color.YELLOW);
            mPaint.setTextSize(mEventLayoutTextSize);
        } else {
            mPaint.setColor(mEventLayoutTextColor);
            mPaint.setTextSize(mEventLayoutTextSize);
        }

        //NEW CHANGES USING SHOW_TYPE of EVENT
        String title = null;

        title = event.getTitle();

        title = title.substring(0, mPaint.breakText(title, true, drawingRect.right - drawingRect.left, null));

        TextPaint textPaint = new TextPaint(Paint.LINEAR_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
        textPaint.setColor(mPaint.getColor());
        textPaint.setTextSize(mPaint.getTextSize());
        textPaint.setStyle(mPaint.getStyle());

        CharSequence txt = null;

        if (event.getIntStartTime() < mTimeLowerBoundary) {
            //canvas.drawText(title, getXFrom(mTimeLowerBoundary) + 10, drawingRect.top - 5, mPaint);
            txt = TextUtils.ellipsize(title, textPaint, (drawingRect.right - getXFrom(mTimeLowerBoundary)) - 10, TextUtils.TruncateAt.END);
            canvas.drawText(txt, 0, txt.length(), getXFrom(mTimeLowerBoundary) + 10, drawingRect.top, textPaint);
        } else {
            //canvas.drawText(title, drawingRect.left, drawingRect.top - 5, mPaint);
            txt = TextUtils.ellipsize(title, textPaint, (drawingRect.right - drawingRect.left) - 10, TextUtils.TruncateAt.END);
            canvas.drawText(txt, 0, txt.length(), drawingRect.left, drawingRect.top, textPaint);
        }
    }

    private void setEventDrawingRectangle(final int channelPosition, final long start, final long end, final Rect drawingRect, String eventName) {
        if (start < mTimeOffset) {
            drawingRect.left = getXFrom(mTimeOffset);
        } else {
            drawingRect.left = getXFrom(start);
        }

        drawingRect.top = getTopFrom(channelPosition);
        drawingRect.right = getXFrom(end) - mChannelLayoutMargin;

        drawingRect.bottom = drawingRect.top + mChannelLayoutHeight;
    }

    private int getFirstVisibleChannelPosition() {
        final int y = getScrollY();
        int position = (y - mChannelLayoutMargin - mTimeBarHeight) / (mChannelLayoutHeight + mChannelLayoutMargin);

        if (position < 0) {
            position = 0;
        }
        return position;
    }

    private int getLastVisibleChannelPosition() {
        final int y = getScrollY();
        final int totalChannelCount = epgData.getChannelCount();
        final int screenHeight = getHeight();
        int position = (y + screenHeight + mTimeBarHeight - mChannelLayoutMargin) / (mChannelLayoutHeight + mChannelLayoutMargin);

        if (position > totalChannelCount - 1) {
            position = totalChannelCount - 1;
        }

        // Add one extra row if we don't fill screen with current..
        return (y + screenHeight) > (position * mChannelLayoutHeight) && position < totalChannelCount - 1 ? position + 1 : position;
    }

    private int getLastBlankLineChannelPosition() {
        final int y = getScrollY();
        final int totalChannelCount = 6;
        final int screenHeight = getHeight();
        int position = (y + screenHeight + mTimeBarHeight - mChannelLayoutMargin) / (mChannelLayoutHeight + mChannelLayoutMargin);

        if (position > totalChannelCount - 1) {
            position = totalChannelCount - 1;
        }

        // Add one extra row if we don't fill screen with current..
        return (y + screenHeight) > (position * mChannelLayoutHeight) && position < totalChannelCount - 1 ? position + 1 : position;
    }

    private boolean isEventVisible(final long start, final long end) {
        return (start >= mTimeLowerBoundary && start <= mTimeUpperBoundary)
                || (end >= mTimeLowerBoundary && end <= mTimeUpperBoundary)
                || (start <= mTimeLowerBoundary && end >= mTimeUpperBoundary);
    }

    private void drawChannelItem(final Canvas canvas, int position, Rect drawingRect) {
        Rect drawingRect1 = new Rect();
        drawingRect.left = getScrollX();
        drawingRect.top = getTopFrom(position);
        drawingRect.right = drawingRect.left + mChannelLayoutWidth / 2;
        drawingRect.bottom = drawingRect.top + mChannelLayoutHeight;

        //mPaint.setColor(mChannelLayoutBackground);
        mPaint.setColor(mRedColor);

        canvas.drawRect(drawingRect, mPaint);

        mPaint.setTextAlign(Paint.Align.CENTER);
        //Channel-no
        //mPaint.setColor(mEventLayoutTextColor);
        mPaint.setColor(mColorPrimaryDark);
        mPaint.setTextSize(mEventLayoutTextSize - 2);
        canvas.drawText(Long.toString(epgData.getChannel(position).getChannelNumber()), drawingRect.centerX(), drawingRect.centerY() + 10, mPaint);

        drawingRect1.left = getScrollX() + mChannelLayoutWidth / 2;
        drawingRect1.top = getTopFrom(position);
        drawingRect1.right = drawingRect1.left + mChannelLayoutWidth / 2;
        drawingRect1.bottom = drawingRect1.top + mChannelLayoutHeight;

        mPaint.setColor(mTimeBarLineColor);
        canvas.drawRect(drawingRect1, mPaint);

        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setColor(mColorPrimaryDark);
        mPaint.setTextSize(mEventLayoutTextSize - 2);
        canvas.drawText(epgData.getChannel(position).getName(), drawingRect1.centerX(), drawingRect1.centerY() + 10, mPaint);
    }

    void resetBoundaries() {
        mMillisPerPixel = calculateMillisPerPixel();
        mTimeOffset = calculatedBaseLine();
        mTimeLowerBoundary = getTimeFrom(0);
        mTimeUpperBoundary = getTimeFrom(getWidth());
    }

    private long calculateMillisPerPixel() {
        return HOURS_IN_VIEWPORT_MILLIS / (getResources().getDisplayMetrics().widthPixels - mChannelLayoutWidth - mChannelLayoutMargin);
    }

    private long calculatedBaseLine() {
        DateTime dateTime = new DateTime(LocalDateTime.now().toDateTime().getMillis()).minusMillis(DAYS_BACK_MILLIS);
        if (DAYS_BACK_MILLIS > 0) {
            //Log.e(TAG, " @ calculatedBaseLine with CU/SO @ " + dateTime.withTimeAtStartOfDay().toString());
            return dateTime.withTimeAtStartOfDay().getMillis();
        } else {
            //Log.e(TAG, " @ calculatedBaseLine @ " + new Date(EPGUtils.roundOfTimeToLowerBound(dateTime.getMillis())));
            return EPGUtil.roundOfTimeToLowerBound(dateTime.getMillis());
        }
    }

    /**
     * @param x 像素值(某个地方距epg起始地方的偏移值)
     * @return 得到x地方的时刻,单位毫秒
     */
    private long getTimeFrom(int x) {
        return (x * mMillisPerPixel) + mTimeOffset;
    }

    /**
     * @param position 可以理解成第几个节目
     * @return 第position节目显示区域顶部位置像素值
     */
    private int getTopFrom(int position) {
        int y = position * (mChannelLayoutHeight + mChannelLayoutMargin) + mChannelLayoutMargin + mTimeBarHeight;
        return y;
    }

    private int getXFrom(long time) {
        return (int) ((time - mTimeOffset) / mMillisPerPixel) + mChannelLayoutMargin + mChannelLayoutWidth + mChannelLayoutMargin;
    }

    public int getServiceIndexInList(int channelNo) {
        for (int i = 0; i < serviceList.size(); ++i) {
            if (serviceList.get(i).getChannelNumber() == channelNo)
                return i;
        }
        return 0;
    }

    private int getXPositionStart() {
        //Log.e(TAG, " @ @ getXPositionStart @ @ " + new Date(EPGUtils.roundOfTimeToLowerBound(System.currentTimeMillis())));
        if (DAYS_BACK_MILLIS > 0) {
            int temp = getXFrom(EPGUtil.roundOfTimeToLowerBound(System.currentTimeMillis())) - mChannelLayoutMargin - mChannelLayoutWidth;
            //Log.e(TAG, " @ @ getXPositionStart @ @ " + temp);
            return temp;
        } else {
            return 0;
        }
    }

    private boolean isEventStartTimeVisible(final long start) {
        return (start >= mTimeLowerBoundary || start <= mTimeUpperBoundary);
    }

    private Rect calculateProgramsHitArea() {
        mMeasuringRect.top = mTimeBarHeight;
        int visibleChannelsHeight = epgData.getChannelCount() * (mChannelLayoutHeight + mChannelLayoutMargin);
        mMeasuringRect.bottom = visibleChannelsHeight < getHeight() ? visibleChannelsHeight : getHeight();
        mMeasuringRect.left = mChannelLayoutWidth;
        mMeasuringRect.right = getWidth();
        return mMeasuringRect;
    }

    public void moveRight() {
        if (currentProgram != null) {
            List<EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean> events = epgData.getEvents(currentChannelPosition);
            if (events != null && events.size() > 0 && (currentProgram.getIntStartTime() == events.get(events.size() - 1).getIntStartTime())) {
                //Log.d("wujiang", "moveRight: it is last event");
                return;
            }

            isMoveRight = true;
            isMoveLeft = false;
            gotoProgram(currentChannelPosition, currentProgram.getIntStopTime() + 1);
            invalidate();

            int x = 0;

            long dur = currentProgram.getIntStopTime() - currentProgram.getIntStartTime();
            long currentUpperBound = EPGUtil.roundOfTimeToLowerBound(currentProgram.getIntStartTime()) + HOURS_IN_VIEWPORT_MILLIS;
            if (dur > HOURS_IN_VIEWPORT_MILLIS && !isEventStartTimeVisible(currentProgram.getIntStartTime())) {
                //Log.d("wujiang", "moveRight: 1111111111111111");
                if (EPGUtil.roundOfTimeToLowerBound(currentProgram.getIntStartTime()) != currentProgram.getIntStartTime()) {
                    x = getXFrom(currentProgram.getIntStartTime() + ((30 * 60 * 1000) - (currentProgram.getIntStartTime() - EPGUtil.roundOfTimeToLowerBound(currentProgram.getIntStartTime()))));
                } else {
                    x = getXFrom(currentProgram.getIntStartTime() + (HOURS_IN_VIEWPORT_MILLIS - 30 * 60 * 1000));
                }
                //x = getXFrom((currentProgram.getStart() - EPGUtils.roundOfTimeToLowerBound(currentProgram.getStart())) + HOURS_IN_VIEWPORT_MILLIS);
            } else if (dur > HOURS_IN_VIEWPORT_MILLIS) {
                //Log.d("wujiang", "moveRight: 22222222222");
                if (EPGUtil.roundOfTimeToLowerBound(currentProgram.getIntStartTime()) != currentProgram.getIntStartTime()) {
                    x = getXFrom(currentProgram.getIntStartTime() + ((60 * 60 * 1000) - ((currentProgram.getIntStartTime() - EPGUtil.roundOfTimeToLowerBound(currentProgram.getIntStartTime())))));
                } else {
                    x = getXFrom(currentProgram.getIntStartTime() + (HOURS_IN_VIEWPORT_MILLIS - 60 * 60 * 1000));
                }
            } else if (EPGUtil.roundOfTimeToLowerBound(currentProgram.getIntStartTime()) != currentProgram.getIntStartTime()) {
                //Log.d("wujiang", "moveRight: 33333333333333");
                x = getXFrom(currentProgram.getIntStartTime() + ((30 * 60 * 1000) - (currentProgram.getIntStartTime() - EPGUtil.roundOfTimeToLowerBound(currentProgram.getIntStartTime()))));
            } else {
                //Log.d("wujiang", "moveRight: 444444444444444");
                x = getXFrom(currentProgram.getIntStartTime() + (30 * 60 * 1000));
            }

            //EPGUtils.printTime("MoveRight", mTimeUpperBoundary);
            //int x = getXFrom(currentProgram.getEndTime());

            //Log.d("wujiang", "moveRight: x = " + x);
            //Log.d("wujiang", "moveRight: getScrollX() = " + getScrollX());
            //Log.d("wujiang", "moveRight: getWidth() = " + getWidth());
            int programAreaX = calculateProgramsHitArea().right + getScrollX();

            //Log.d("wujiang", "moveRight: calculateProgramsHitArea().right = " + calculateProgramsHitArea().right);

            if (x > programAreaX) {
                scrollBy(x - programAreaX - 30, 0);
            }
        }
    }

    public void moveLeft() {
        if (currentProgram != null) {
            if (currentProgram.getIntStartTime() <= mTimeOffset) {
                //Log.d("wujiang", "moveLeft: 1111111");
                return;
            }

            isMoveRight = false;
            isMoveLeft = true;
            gotoProgram(currentChannelPosition, currentProgram.getIntStartTime() - 1);
            invalidate();
            int x = 0;//getXFrom(currentProgram.getStartTime());
            if (currentProgram.getIntStartTime() < mTimeOffset) {
                x = getXFrom(mTimeOffset);
            } else {
                x = getXFrom(EPGUtil.roundOfTimeToLowerBound(currentProgram.getIntStartTime()));
            }

            int programAreaX = calculateProgramsHitArea().left + getScrollX();
            if (x < programAreaX) {
                scrollBy(x - programAreaX, 0);
            }
        } else {
            Log.e("wujiang", " @ MoveLeft @ I think CatchUp is enabled");
        }
    }

    public boolean moveDown() {
        if (currentProgram != null) {
            isMoveRight = false;
            isMoveLeft = false;
            long time = 0;

            if (referenceEvent.getIntStartTime() < mTimeOffset) {
                time = mTimeOffset + 1;
            } else if (referenceEvent.isCurrent() && referenceEvent.getIntStartTime() < EPGUtil.roundOfTimeToLowerBound(System.currentTimeMillis())) {
                time = EPGUtil.roundOfTimeToLowerBound(System.currentTimeMillis()) + 1;
            } else {
                time = EPGUtil.roundOfTimeToLowerBound(referenceEvent.getIntStartTime()) + 1;
            }
            //Log.e("wujiang", " moveDown: mTimeOffset = " + mTimeOffset);
            //Log.e("wujiang", " moveDown: currentChannelPosition = " + currentChannelPosition);
            //Log.e("wujiang", " moveDown: time = " + time);

            gotoProgram(currentChannelPosition + 1, time);
            invalidate();
            int y = getTopFrom(currentChannelPosition);
            int programAreaY = calculateProgramsHitArea().bottom + getScrollY() - mChannelLayoutHeight;
            if (y > programAreaY) {
                scrollBy(0, y - programAreaY);
            }

            if (currentChannelPosition >= (epgData.getChannelCount() - 1)) {
                //Log.d("wujiang", "moveDown: 11111111111");
                return true;
            }
        }

        //Log.d("wujiang", "moveDown: 2222222222");
        return false;
    }

    public void moveUp() {
        if (currentProgram != null) {
            isMoveRight = false;
            isMoveLeft = false;
            //ORG
            //long time = (currentProgram.getStartTime() + currentProgram.getEndTime()) / 2;
            long time = 0;

            if (referenceEvent.getIntStartTime() < mTimeOffset) {
                time = mTimeOffset + 1;
            } else if (referenceEvent.isCurrent() && referenceEvent.getIntStartTime() < EPGUtil.roundOfTimeToLowerBound(System.currentTimeMillis())) {
                time = EPGUtil.roundOfTimeToLowerBound(System.currentTimeMillis()) + 1;
            } else {
                time = EPGUtil.roundOfTimeToLowerBound(referenceEvent.getIntStartTime()) + 1;
            }
            gotoProgram(currentChannelPosition - 1, time);
            invalidate();
            int y = getTopFrom(currentChannelPosition);
            int programAreaY = calculateProgramsHitArea().top + getScrollY();
            if (y < programAreaY) {
                scrollBy(0, y - programAreaY);
            }
        }
    }

    public void moveToDestPosition(int position, int direction) {
        if (currentProgram != null) {
            isMoveRight = false;
            isMoveLeft = false;
            long time = 0;

            if (referenceEvent.getIntStartTime() < mTimeOffset) {
                time = mTimeOffset + 1;
            } else if (referenceEvent.isCurrent() && referenceEvent.getIntStartTime() < EPGUtil.roundOfTimeToLowerBound(System.currentTimeMillis())) {
                time = EPGUtil.roundOfTimeToLowerBound(System.currentTimeMillis()) + 1;
            } else {
                time = EPGUtil.roundOfTimeToLowerBound(referenceEvent.getIntStartTime()) + 1;
            }

            gotoProgram(position, time);
            invalidate();
            int y = getTopFrom(position);

            if (direction == UP_DIRECTION) {
                int programAreaY = calculateProgramsHitArea().top + getScrollY();
                if (y < programAreaY) {
                    scrollBy(0, y - programAreaY);
                }
            } else {
                int programAreaY = calculateProgramsHitArea().bottom + getScrollY() - mChannelLayoutHeight;
                if (y > programAreaY) {
                    scrollBy(0, y - programAreaY);
                }
            }
        }
    }
}

 这里重点是如下几个函数:drawEvents,drawTimebar,drawTimeLine,moveToDestPosition。

2、在显示epg信息的activity里的布局文件中使用自定义EPG View,代码如下:

<!-- 时刻表、节目列表和7天epg -->
<RelativeLayout
    android:id="@+id/epg_view_area"
    android:layout_width="match_parent"
    android:layout_height="235dp"
    android:layout_alignParentBottom="true"
    android:background="@android:color/transparent"
    android:visibility="gone">

    <!-- epg 信息的当前时间、节目列表 -->
    <LinearLayout
        android:id="@+id/recyclerView_channel_list_area"
        android:layout_width="272dp"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <!-- epg 信息的当前时间 -->
        <TextView
            android:id="@+id/epg_date"
            android:layout_width="match_parent"
            android:layout_height="31dp"
            android:background="@color/color_epg_focus"
            android:gravity="center"
            android:textColor="@color/epg_event_layout_text" />

        <!-- 节目列表 -->
        <ListView
            android:id="@+id/listview_channel_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/translucent_black"
            android:dividerHeight="1dp"
            android:listSelector="@drawable/epg_channel_recyclerview_item_selector">
        </ListView>
    </LinearLayout>

    <!-- 7天EPG信息 -->
    <com.amlogic.dvb_custom_view.EpgView
        android:id="@+id/epg_view"
        android:layout_width="700dp"
        android:layout_height="match_parent"
        android:layout_toRightOf="@+id/recyclerView_channel_list_area">
    </com.amlogic.dvb_custom_view.EpgView>

</RelativeLayout>
listview_channel_list是显示节目名称的listview,在它的上方显示的是当前EPG信息所属的时间。

3、进入DVB时加载所有节目的EPG信息,一般是7天的EPG。这个时候显示EPG信息的那个activity还没有显示。

public static HashMap<ServiceInfoEntity, List<EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean>> result;

  这是一个哈希列表,Key对应的是节目,Value对应的是这个节目7天EPG的链表。

for (int i = 0; i < channel_list.size(); i++) {
    ServiceInfoEntity serviceObj = channel_list.get(i);
    result.put(serviceObj, loadEpgFromDB(serviceObj, i));
}

  把所有节目节目的epg信息存放到result里。

4、在显示EPG信息的activity里加载epg信息,并可以上下左右切换。

public static HashMap<ServiceInfoEntity, List<EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean>> mResult;
public static EPGData mEpgData;

  //节目一般情况下会有分组,下面的代码是根据组的index过滤出对应的节目

List<ServiceInfoEntity> serviceInfoEntities = ChannelListUtils.getServicesFromCachedAndDb(AndroidNineMainMenu.this, mChannelGruopInfoList.get(position));

  //加载组里的节目对用的EPG信息

mResult.clear();

for (int i = 0; i < serviceInfoEntities.size(); i++) {
    ServiceInfoEntity serviceInfoEntity = serviceInfoEntities.get(i);

    //DVBPlayer.result就是第3步那里的result
    if (DVBPlayer.result.get(serviceInfoEntity) != null) {
        mResult.put(serviceInfoEntity, DVBPlayer.result.get(serviceInfoEntity));
    }
}

mEpgData = new EPGDataImpl(mResult);
mEpgData.cleanSelection();
mChannelListviewAdapter.setEpgData(mEpgData);
mEpgView.setEPGData(AndroidNineMainMenu.this, mEpgData);
mEpgView.recalculateAndRedraw(false, false);

  相关类的代码

public interface EPGData {
    ServiceInfoEntity getChannel(int position);

    List<EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean> getEvents(int channelPosition);

    List<ServiceInfoEntity> getChannels();

    //CircularArray<Event> getEventsC(int channelPosition);

    EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean getEvent(int channelPosition, int programPosition);

    String getStartOverStatus(EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean event);

    String getCatchUpStatus(EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean event);

    int getChannelCount();

    boolean hasData();

    void cleanSelection();
}
public class EPGDataImpl implements EPGData {
    private List<ServiceInfoEntity> channels = Lists.newArrayList();
    private List<List<EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean>> events = Lists.newArrayList();


    public EPGDataImpl(Map<ServiceInfoEntity, List<EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean>> data) {

        if (data == null || data.isEmpty()) {
            Log.d("wujiang", "EPGDataImpl: data == null || data.isEmpty()");
            return;
        }
        channels = Lists.newArrayList(data.keySet());
        events = Lists.newArrayList(data.values());

        Log.d("wujiang", "EPGDataImpl: channels size = " + channels.size());
        Log.d("wujiang", "EPGDataImpl: events size = " + events.size());
    }

    public List<ServiceInfoEntity> getChannels() {
        return channels;
    }

    public ServiceInfoEntity getChannel(int position) {
        if (channels == null || channels.size() < 1) {
            return null;
        } else {
            return channels.get(position);
        }

    }

    public List<EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean> getEvents(int channelPosition) {
        if (events == null || events.size() < 1) {
            return null;
        } else {
            return events.get(channelPosition);
        }
    }

    public EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean getEvent(int channelPosition, int programPosition) {
        EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean e = null;

        try {
            e = events.get(channelPosition).get(programPosition);
        } catch (Exception ex) {
            Log.e("EPGImpl", "" + Log.getStackTraceString(ex));
            Log.e("EPGImpl", "channelPosition " + channelPosition + " programPosition " + programPosition);
        }
        return e;
    }

    @Override
    public String getCatchUpStatus(EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean event) {
        /*ServiceInfoEntity tmp = null;
        long chNo = event.getChannelNumber();
        for(ServiceInfoEntity s : channels) {
            if(s.getChannelNumber() == chNo) {
                tmp = s;
            } else {
                tmp = channels.get(0);
            }
        }

        if(tmp == null)
            tmp = channels.get(0);

        return tmp.getCatchup();*/

        return null;
    }

    @Override
    public String getStartOverStatus(EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean event) {
       /* ServiceInfoEntity tmp = null;
        long chNo = event.getChannelNumber();
        for(ServiceInfoEntity s : channels) {
            if(s.getChannelNumber() == chNo) {
                tmp = s;
            } else {
                tmp = channels.get(0);
            }
        }

        if(tmp == null)
            tmp = channels.get(0);

        return tmp.getStartover();*/
        return null;
    }

    public int getChannelCount() {
        return channels.size();

    }

    @Override
    public boolean hasData() {
        return !channels.isEmpty();
    }

    @Override
    public void cleanSelection() {
        for (List<EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean> channelEvents : this.events) {
            for (EnhancedScheduleGridBean.ScheduleGridBean.ChannelBean.ProgrammeBean event : channelEvents) {
                if (event.isSelected()) event.setSelected(false);
            }
        }
    }
}

  当焦点在listview_channel_list时按上下切换epg信息。

/* 显示节目名的ListView Item Selected响应函数 */
mChannelListView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        mChannelListRecyclerViewCurrentPosition = position;
        Log.d("wujiang", "mChannelListView->onItemSelected: mChannelListRecyclerViewCurrentPosition = " + mChannelListRecyclerViewCurrentPosition);
        Log.d("wujiang", "mChannelListView->onItemSelected: mEpgView.currentChannelPosition = " + mEpgView.currentChannelPosition);

        if (mEpgView.currentChannelPosition >= 0) {
            if (position > mEpgView.currentChannelPosition) {
                mEpgView.moveToDestPosition(position, EpgView.DOWN_DIRECTION);
            } else if (position < mEpgView.currentChannelPosition) {
                mEpgView.moveToDestPosition(position, EpgView.UP_DIRECTION);
            }
        }
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }
});

  //左右键切换epg信息

mEpgView.moveLeft();
mEpgView.moveRight();

我这里贴出的都是关键性的代码,如果你确实有需求,那你得好好研究这些代码,肯定对你是有用的。

                                                                     The             End

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值